<!DOCTYPE html>
<html lang="zh-CN,en,ja-JP">
    <head hexo-theme='https://github.com/volantis-x/hexo-theme-volantis/#5.8.0'>
  <meta name="generator" content="Hexo 6.3.0">
  <meta name="Volantis" content="5.8.0">
  <meta charset="utf-8">
  <!-- SEO相关 -->
  
  <link rel="canonical" href="https://CS0522.gitee.io/ja-jp/docs/atlantis-project/"/>
  <!-- 渲染优化 -->
    <meta http-equiv='x-dns-prefetch-control' content='on' />
      <link rel='dns-prefetch' href='https://unpkg.com'>
      <link rel="preconnect" href="https://unpkg.com" crossorigin>
  <meta name="renderer" content="webkit">
  <meta name="force-rendering" content="webkit">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
    <meta http-equiv="Content-Security-Policy" content=" default-src 'self' https:; block-all-mixed-content; base-uri 'self' https:; form-action 'self' https:; worker-src 'self' https:; connect-src 'self' https: *; img-src 'self' data: https: *; media-src 'self' https: *; font-src 'self' data: https: *; frame-src 'self' https: *; manifest-src 'self' https: *; child-src https:; script-src 'self' https: 'unsafe-inline' *; style-src 'self' https: 'unsafe-inline' *; ">
  <meta name="HandheldFriendly" content="True" >
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5">
  <meta content="black-translucent" name="apple-mobile-web-app-status-bar-style">
  <meta content="telephone=no" name="format-detection">
  <!-- import head_begin begin -->
  <!-- import head_begin end -->
  <!-- Custom Files headBegin begin-->
  
  <!-- Custom Files headBegin end-->
  <!-- front-matter head_begin begin -->
  <!-- front-matter head_begin end -->
    <link rel="shortcut icon" type='image/x-icon' href="/images/cicon.ico">
  <link rel="preload" href="/css/style.css" as="style">
  <link rel="preload" href="https://unpkg.com/volantis-static@0.0.1654736714924/media/fonts/UbuntuMono/UbuntuMono-Regular.ttf" as="font" type="font/ttf" crossorigin="anonymous">
<link rel="preload" href="https://unpkg.com/volantis-static@0.0.1654736714924/media/fonts/UbuntuMono/UbuntuMono-Regular.ttf" as="font" type="font/ttf" crossorigin="anonymous">

  <!-- feed -->
  <!-- 页面元数据 -->
  <title>【文档小记】Atlantis JMVT 游戏车队交流平台 - 诚实同学的博客</title>
  <meta name="keywords" content="Atlantis JMVT,Vue,SpringBoot,WebSite,前端,后端,个人博客, 计算机, 学习">
  <meta desc name="description" content="记录了这个 Vue + SpringBoot 前后端项目开发的一些知识点以及解决方案 - Chen Shi - 诚实同学的博客">
  
<meta property="og:type" content="article">
<meta property="og:title" content="【文档小记】Atlantis JMVT 游戏车队交流平台">
<meta property="og:url" content="https://cs0522.gitee.io/ja-JP/docs/atlantis-project/index.html">
<meta property="og:site_name" content="诚实同学的博客">
<meta property="og:description" content="记录了这个 Vue + SpringBoot 前后端项目开发的一些知识点以及解决方案">
<meta property="og:locale" content="ja_JP">
<meta property="og:image" content="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png">
<meta property="article:published_time" content="2023-10-25T13:19:17.000Z">
<meta property="article:modified_time" content="2023-11-12T02:56:03.720Z">
<meta property="article:author" content="Chen Shi">
<meta property="article:tag" content="Atlantis JMVT">
<meta property="article:tag" content="Vue">
<meta property="article:tag" content="SpringBoot">
<meta property="article:tag" content="WebSite">
<meta property="article:tag" content="前端">
<meta property="article:tag" content="后端">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png">
  <style>
    /* 首屏样式 */
    #safearea {
  display: none;
}
.post-story + .post-story {
  content-visibility: auto;
  contain-intrinsic-size: 10px 500px;
}
:root {
  --color-site-body: #f4f4f4;
  --color-site-bg: #f4f4f4;
  --color-site-inner: #fff;
  --color-site-footer: #666;
  --color-card: #fff;
  --color-text: #444;
  --color-block: #f6f6f6;
  --color-inlinecode: #c74f00;
  --color-codeblock: #fff7ea;
  --color-h1: #3a3a3a;
  --color-h2: #3a3a3a;
  --color-h3: #333;
  --color-h4: #444;
  --color-h5: #555;
  --color-h6: #666;
  --color-p: #444;
  --color-list: #666;
  --color-list-hl: #30ad91;
  --color-meta: #888;
  --color-read-bkg: #e0d8c8;
  --color-read-post: #f8f1e2;
  --color-copyright-bkg: #f5f5f5;
}
* {
  box-sizing: border-box;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  outline: none;
  margin: 0;
  padding: 0;
}
*::-webkit-scrollbar {
  height: 4px;
  width: 4px;
}
*::-webkit-scrollbar-track-piece {
  background: transparent;
}
*::-webkit-scrollbar-thumb {
  background: #3dd9b6;
  cursor: pointer;
  border-radius: 2px;
  -webkit-border-radius: 2px;
}
*::-webkit-scrollbar-thumb:hover {
  background: #ff5722;
}
html {
  color: var(--color-text);
  width: 100%;
  height: 100%;
  font-family: UbuntuMono, "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Menlo, Monaco, monospace, sans-serif;
  font-size: 16px;
}
html >::-webkit-scrollbar {
  height: 4px;
  width: 4px;
}
html >::-webkit-scrollbar-track-piece {
  background: transparent;
}
html >::-webkit-scrollbar-thumb {
  background: #54b5a0 linear-gradient(45deg, rgba(255,255,255,0.4) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.4) 50%, rgba(255,255,255,0.4) 75%, transparent 75%, transparent);
  cursor: pointer;
  border-radius: 2px;
  -webkit-border-radius: 2px;
}
html >::-webkit-scrollbar-thumb:hover {
  background: #54b5a0 linear-gradient(45deg, rgba(255,255,255,0.4) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.4) 50%, rgba(255,255,255,0.4) 75%, transparent 75%, transparent);
}
body {
  background-color: var(--color-site-body);
  text-rendering: optimizelegibility;
  -webkit-tap-highlight-color: rgba(0,0,0,0);
  line-height: 1.6;
  -webkit-text-size-adjust: 100%;
  -ms-text-size-adjust: 100%;
}
body.modal-active {
  overflow: hidden;
}
@media screen and (max-width: 680px) {
  body.modal-active {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
  }
}
a {
  color: #2092ec;
  cursor: pointer;
  text-decoration: none;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
a:hover {
  color: #ff5722;
}
a:active,
a:hover {
  outline: 0;
}
ul,
ol {
  padding-left: 0;
}
ul li,
ol li {
  list-style: none;
}
header {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
}
img {
  border: 0;
  background: none;
  max-width: 100%;
}
svg:not(:root) {
  overflow: hidden;
}
hr {
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  height: 0;
  border: 0;
  border-radius: 1px;
  -webkit-border-radius: 1px;
  border-bottom: 1px solid rgba(68,68,68,0.1);
}
button,
input {
  color: inherit;
  font: inherit;
  margin: 0;
}
button {
  overflow: visible;
  text-transform: none;
  -webkit-appearance: button;
  cursor: pointer;
}
@supports (backdrop-filter: blur(20px)) {
  .blur {
    background: rgba(255,255,255,0.9) !important;
    backdrop-filter: saturate(200%) blur(20px);
  }
}
.shadow {
  box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1);
  -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1);
}
.shadow.floatable {
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
.shadow.floatable:hover {
  box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1);
  -webkit-box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1);
}
#l_cover {
  min-height: 64px;
}
.cover-wrapper {
  top: 0;
  left: 0;
  max-width: 100%;
  height: 100vh;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  flex-wrap: nowrap;
  -webkit-flex-wrap: nowrap;
  -khtml-flex-wrap: nowrap;
  -moz-flex-wrap: nowrap;
  -o-flex-wrap: nowrap;
  -ms-flex-wrap: nowrap;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  -webkit-box-orient: vertical;
  -moz-box-orient: vertical;
  -webkit-flex-direction: column;
  -ms-flex-direction: column;
  flex-direction: column;
  align-items: center;
  align-self: center;
  align-content: center;
  color: var(--color-site-inner);
  padding: 0 16px;
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  position: relative;
  overflow: hidden;
  margin-bottom: -100px;
}
.cover-wrapper .cover-body {
  z-index: 1;
  position: relative;
  width: 100%;
  height: 100%;
}
.cover-wrapper#full {
  height: calc(100vh + 100px);
  padding-bottom: 100px;
}
.cover-wrapper#half {
  max-height: 640px;
  min-height: 400px;
  height: calc(36vh - 64px + 200px);
}
.cover-wrapper #scroll-down {
  width: 100%;
  height: 64px;
  position: absolute;
  bottom: 100px;
  text-align: center;
  cursor: pointer;
}
.cover-wrapper #scroll-down .scroll-down-effects {
  color: #fff;
  font-size: 24px;
  line-height: 64px;
  position: absolute;
  width: 24px;
  left: calc(50% - 12px);
  text-shadow: 0 1px 2px rgba(0,0,0,0.1);
  animation: scroll-down-effect 1.5s infinite;
  -webkit-animation: scroll-down-effect 1.5s infinite;
  -khtml-animation: scroll-down-effect 1.5s infinite;
  -moz-animation: scroll-down-effect 1.5s infinite;
  -o-animation: scroll-down-effect 1.5s infinite;
  -ms-animation: scroll-down-effect 1.5s infinite;
}
@-moz-keyframes scroll-down-effect {
  0% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
  50% {
    top: -16px;
    opacity: 0.4;
    -webkit-opacity: 0.4;
    -moz-opacity: 0.4;
  }
  100% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@-webkit-keyframes scroll-down-effect {
  0% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
  50% {
    top: -16px;
    opacity: 0.4;
    -webkit-opacity: 0.4;
    -moz-opacity: 0.4;
  }
  100% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@-o-keyframes scroll-down-effect {
  0% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
  50% {
    top: -16px;
    opacity: 0.4;
    -webkit-opacity: 0.4;
    -moz-opacity: 0.4;
  }
  100% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@keyframes scroll-down-effect {
  0% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
  50% {
    top: -16px;
    opacity: 0.4;
    -webkit-opacity: 0.4;
    -moz-opacity: 0.4;
  }
  100% {
    top: 0;
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
.cover-wrapper .cover-body {
  margin-top: 64px;
  margin-bottom: 100px;
}
.cover-wrapper .cover-body,
.cover-wrapper .cover-body .top,
.cover-wrapper .cover-body .bottom {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  -webkit-box-orient: vertical;
  -moz-box-orient: vertical;
  -webkit-flex-direction: column;
  -ms-flex-direction: column;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  -webkit-justify-content: center;
  -khtml-justify-content: center;
  -moz-justify-content: center;
  -o-justify-content: center;
  -ms-justify-content: center;
  max-width: 100%;
}
.cover-wrapper .cover-body .bottom {
  margin-top: 32px;
}
.cover-wrapper .cover-body .title {
  font-family: UbuntuMono, "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Helvetica, monospace;
  font-size: 3.125rem;
  line-height: 1.2;
  text-shadow: 0 1px 2px rgba(0,0,0,0.1);
}
.cover-wrapper .cover-body .subtitle {
  font-size: 20px;
}
.cover-wrapper .cover-body .logo {
  max-height: 120px;
  max-width: calc(100% - 4 * 16px);
}
@media screen and (min-height: 1024px) {
  .cover-wrapper .cover-body .title {
    font-size: 3rem;
  }
  .cover-wrapper .cover-body .subtitle {
    font-size: 1.05rem;
  }
  .cover-wrapper .cover-body .logo {
    max-height: 150px;
  }
}
.cover-wrapper .cover-body .m_search {
  position: relative;
  max-width: calc(100% - 16px);
  width: 320px;
  vertical-align: middle;
}
.cover-wrapper .cover-body .m_search .form {
  position: relative;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  width: 100%;
}
.cover-wrapper .cover-body .m_search .icon,
.cover-wrapper .cover-body .m_search .input {
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
.cover-wrapper .cover-body .m_search .icon {
  position: absolute;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  line-height: 2.5rem;
  width: 32px;
  top: 0;
  left: 5px;
  color: rgba(68,68,68,0.75);
}
.cover-wrapper .cover-body .m_search .input {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  height: 2.5rem;
  width: 100%;
  box-shadow: none;
  -webkit-box-shadow: none;
  box-sizing: border-box;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  font-size: 0.875rem;
  -webkit-appearance: none;
  padding-left: 36px;
  border-radius: 1.4rem;
  -webkit-border-radius: 1.4rem;
  background: rgba(255,255,255,0.6);
  backdrop-filter: blur(10px);
  border: none;
  color: var(--color-text);
}
@media screen and (max-width: 500px) {
  .cover-wrapper .cover-body .m_search .input {
    padding-left: 36px;
  }
}
.cover-wrapper .cover-body .m_search .input:hover {
  background: rgba(255,255,255,0.8);
}
.cover-wrapper .cover-body .m_search .input:focus {
  background: #fff;
}
.cover-wrapper .list-h {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  -webkit-box-orient: horizontal;
  -moz-box-orient: horizontal;
  -webkit-flex-direction: row;
  -ms-flex-direction: row;
  flex-direction: row;
  flex-wrap: wrap;
  -webkit-flex-wrap: wrap;
  -khtml-flex-wrap: wrap;
  -moz-flex-wrap: wrap;
  -o-flex-wrap: wrap;
  -ms-flex-wrap: wrap;
  align-items: stretch;
  border-radius: 4px;
  -webkit-border-radius: 4px;
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
}
.cover-wrapper .list-h a {
  -webkit-box-flex: 1;
  -moz-box-flex: 1;
  -webkit-flex: 1 0;
  -ms-flex: 1 0;
  flex: 1 0;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  font-weight: 600;
}
.cover-wrapper .list-h a img {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  border-radius: 2px;
  -webkit-border-radius: 2px;
  margin: 4px;
  min-width: 40px;
  max-width: 44px;
}
@media screen and (max-width: 768px) {
  .cover-wrapper .list-h a img {
    min-width: 36px;
    max-width: 40px;
  }
}
@media screen and (max-width: 500px) {
  .cover-wrapper .list-h a img {
    margin: 2px 4px;
    min-width: 32px;
    max-width: 36px;
  }
}
@media screen and (max-width: 375px) {
  .cover-wrapper .list-h a img {
    min-width: 28px;
    max-width: 32px;
  }
}
.cover-wrapper {
  max-width: 100%;
}
.cover-wrapper.search .bottom .menu {
  margin-top: 16px;
}
.cover-wrapper.search .bottom .menu .list-h a {
  white-space: nowrap;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  -webkit-box-orient: horizontal;
  -moz-box-orient: horizontal;
  -webkit-flex-direction: row;
  -ms-flex-direction: row;
  flex-direction: row;
  align-items: baseline;
  padding: 2px;
  margin: 4px;
  color: var(--color-site-inner);
  opacity: 0.75;
  -webkit-opacity: 0.75;
  -moz-opacity: 0.75;
  text-shadow: 0 1px 2px rgba(0,0,0,0.05);
  border-bottom: 2px solid transparent;
}
.cover-wrapper.search .bottom .menu .list-h a i {
  margin-right: 4px;
}
.cover-wrapper.search .bottom .menu .list-h a p {
  font-size: 0.9375rem;
}
.cover-wrapper.search .bottom .menu .list-h a:hover,
.cover-wrapper.search .bottom .menu .list-h a.active,
.cover-wrapper.search .bottom .menu .list-h a:active {
  opacity: 1;
  -webkit-opacity: 1;
  -moz-opacity: 1;
  border-bottom: 2px solid var(--color-site-inner);
}
.cover-wrapper #parallax-window {
  position: absolute;
  width: 100%;
  height: 100%;
  background: transparent;
}
.parallax-mirror {
  animation-delay: 0s;
  animation-duration: 0.5s;
  animation-fill-mode: forwards;
  animation-timing-function: ease-out;
  animation-name: fadeIn;
}
@-moz-keyframes fadeIn {
  0% {
    opacity: 0;
    -webkit-opacity: 0;
    -moz-opacity: 0;
    filter: blur(12px);
  }
  100% {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@-webkit-keyframes fadeIn {
  0% {
    opacity: 0;
    -webkit-opacity: 0;
    -moz-opacity: 0;
    filter: blur(12px);
  }
  100% {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@-o-keyframes fadeIn {
  0% {
    opacity: 0;
    -webkit-opacity: 0;
    -moz-opacity: 0;
    filter: blur(12px);
  }
  100% {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@keyframes fadeIn {
  0% {
    opacity: 0;
    -webkit-opacity: 0;
    -moz-opacity: 0;
    filter: blur(12px);
  }
  100% {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@media (prefers-color-scheme: dark) {
  :root {
    --color-mode: 'dark';
  }
  :root:not([color-scheme]) {
    --color-site-body: #121212;
    --color-read-bkg: #1f1f1f;
    --color-read-post: #262626;
    --color-site-bg: #1f1f1f;
    --color-site-inner: rgba(238,238,238,0.871);
    --color-site-footer: rgba(170,170,170,0.871);
    --color-card: #262626;
    --color-text: rgba(238,238,238,0.871);
    --color-block: #434343;
    --color-codeblock: #1f1f1f;
    --color-inlinecode: #d56d28;
    --color-h1: rgba(255,255,255,0.871);
    --color-h2: rgba(255,255,255,0.871);
    --color-h3: rgba(255,255,255,0.6);
    --color-h4: rgba(255,255,255,0.6);
    --color-h5: rgba(255,255,255,0.6);
    --color-h6: rgba(255,255,255,0.6);
    --color-p: rgba(217,217,217,0.871);
    --color-list: rgba(217,217,217,0.871);
    --color-list-hl: #63e0c4;
    --color-meta: rgba(191,191,191,0.871);
    --color-link: rgba(191,191,191,0.871);
    --color-copyright-bkg: #21252b;
  }
  :root:not([color-scheme]) img {
    filter: brightness(70%) !important;
  }
  :root:not([color-scheme]) .blur {
    background: rgba(31,31,31,0.9) !important;
  }
  :root:not([color-scheme]) .white-box.blur {
    background: rgba(38,38,38,0.9) !important;
  }
  :root:not([color-scheme]) .nav-main .u-search-input {
    background: var(--color-card) !important;
  }
  :root:not([color-scheme]) #l_main .article .prev-next>a {
    background: var(--color-block) !important;
  }
  :root:not([color-scheme]) #l_main .article .prev-next>a:hover {
    background: var(--color-site-bg) !important;
  }
  :root:not([color-scheme]) .article blockquote {
    background: var(--color-block) !important;
  }
  :root:not([color-scheme]) .article-title a {
    color: var(--color-h1) !important;
  }
  :root:not([color-scheme]) details>summary {
    color: var(--color-p) !important;
    background: var(--color-site-bg) !important;
  }
  :root:not([color-scheme]) details {
    border: 1px solid var(--color-site-bg) !important;
    background: var(--color-site-bg) !important;
  }
  :root:not([color-scheme]) #u-search .modal,
  :root:not([color-scheme]) #u-search .modal-header,
  :root:not([color-scheme]) #u-search .modal-body {
    background: var(--color-card) !important;
  }
  :root:not([color-scheme]) #u-search .modal-body .modal-results .result:hover {
    background: var(--color-block) !important;
  }
  :root:not([color-scheme]) .u-search-input:hover {
    background: var(--color-block) !important;
  }
  :root:not([color-scheme]) .u-search-input:focus {
    background: var(--color-site-body) !important;
  }
}
[color-scheme='dark'] {
  --color-site-body: #121212;
  --color-read-bkg: #1f1f1f;
  --color-read-post: #262626;
  --color-site-bg: #1f1f1f;
  --color-site-inner: rgba(238,238,238,0.871);
  --color-site-footer: rgba(170,170,170,0.871);
  --color-card: #262626;
  --color-text: rgba(238,238,238,0.871);
  --color-block: #434343;
  --color-codeblock: #1f1f1f;
  --color-inlinecode: #d56d28;
  --color-h1: rgba(255,255,255,0.871);
  --color-h2: rgba(255,255,255,0.871);
  --color-h3: rgba(255,255,255,0.6);
  --color-h4: rgba(255,255,255,0.6);
  --color-h5: rgba(255,255,255,0.6);
  --color-h6: rgba(255,255,255,0.6);
  --color-p: rgba(217,217,217,0.871);
  --color-list: rgba(217,217,217,0.871);
  --color-list-hl: #63e0c4;
  --color-meta: rgba(191,191,191,0.871);
  --color-link: rgba(191,191,191,0.871);
  --color-copyright-bkg: #21252b;
}
[color-scheme='dark'] img {
  filter: brightness(70%) !important;
}
[color-scheme='dark'] .blur {
  background: rgba(31,31,31,0.9) !important;
}
[color-scheme='dark'] .white-box.blur {
  background: rgba(38,38,38,0.9) !important;
}
[color-scheme='dark'] .nav-main .u-search-input {
  background: var(--color-card) !important;
}
[color-scheme='dark'] #l_main .article .prev-next>a {
  background: var(--color-block) !important;
}
[color-scheme='dark'] #l_main .article .prev-next>a:hover {
  background: var(--color-site-bg) !important;
}
[color-scheme='dark'] .article blockquote {
  background: var(--color-block) !important;
}
[color-scheme='dark'] .article-title a {
  color: var(--color-h1) !important;
}
[color-scheme='dark'] details>summary {
  color: var(--color-p) !important;
  background: var(--color-site-bg) !important;
}
[color-scheme='dark'] details {
  border: 1px solid var(--color-site-bg) !important;
  background: var(--color-site-bg) !important;
}
[color-scheme='dark'] #u-search .modal,
[color-scheme='dark'] #u-search .modal-header,
[color-scheme='dark'] #u-search .modal-body {
  background: var(--color-card) !important;
}
[color-scheme='dark'] #u-search .modal-body .modal-results .result:hover {
  background: var(--color-block) !important;
}
[color-scheme='dark'] .u-search-input:hover {
  background: var(--color-block) !important;
}
[color-scheme='dark'] .u-search-input:focus {
  background: var(--color-site-body) !important;
}
@media screen and (max-width: 500px) {
  [color-scheme='dark'] .l_header .m_search {
    background: var(--color-site-bg) !important;
  }
}
@font-face {
  font-family: 'UbuntuMono';
  src: url("https://unpkg.com/volantis-static@0.0.1654736714924/media/fonts/UbuntuMono/UbuntuMono-Regular.ttf");
  font-weight: 'normal';
  font-style: 'normal';
  font-display: swap;
}
@font-face {
  font-family: 'UbuntuMono';
  src: url("https://unpkg.com/volantis-static@0.0.1654736714924/media/fonts/UbuntuMono/UbuntuMono-Regular.ttf");
  font-weight: 'normal';
  font-style: 'normal';
  font-display: swap;
}
.l_header {
  position: fixed;
  z-index: 1000;
  top: 0;
  width: 100%;
  height: 64px;
  background: var(--color-card);
  box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1);
  -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1);
}
.l_header.auto {
  transition: opacity 0.4s ease;
  -webkit-transition: opacity 0.4s ease;
  -khtml-transition: opacity 0.4s ease;
  -moz-transition: opacity 0.4s ease;
  -o-transition: opacity 0.4s ease;
  -ms-transition: opacity 0.4s ease;
  visibility: hidden;
}
.l_header.auto.show {
  opacity: 1 !important;
  -webkit-opacity: 1 !important;
  -moz-opacity: 1 !important;
  visibility: visible;
}
.l_header .container {
  margin-left: 16px;
  margin-right: 16px;
}
.l_header #wrapper {
  height: 100%;
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
}
.l_header #wrapper .nav-main,
.l_header #wrapper .nav-sub {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  flex-wrap: nowrap;
  -webkit-flex-wrap: nowrap;
  -khtml-flex-wrap: nowrap;
  -moz-flex-wrap: nowrap;
  -o-flex-wrap: nowrap;
  -ms-flex-wrap: nowrap;
  justify-content: space-between;
  -webkit-justify-content: space-between;
  -khtml-justify-content: space-between;
  -moz-justify-content: space-between;
  -o-justify-content: space-between;
  -ms-justify-content: space-between;
  align-items: center;
}
.l_header #wrapper .nav-main {
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
.l_header #wrapper.sub .nav-main {
  transform: translateY(-64px);
  -webkit-transform: translateY(-64px);
  -khtml-transform: translateY(-64px);
  -moz-transform: translateY(-64px);
  -o-transform: translateY(-64px);
  -ms-transform: translateY(-64px);
}
.l_header #wrapper .nav-sub {
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
  opacity: 0;
  -webkit-opacity: 0;
  -moz-opacity: 0;
  height: 64px;
  width: calc(100% - 2 * 16px);
  position: absolute;
}
.l_header #wrapper .nav-sub ::-webkit-scrollbar {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
}
@media screen and (min-width: 2048px) {
  .l_header #wrapper .nav-sub {
    max-width: 55vw;
    margin: auto;
  }
}
.l_header #wrapper.sub .nav-sub {
  opacity: 1;
  -webkit-opacity: 1;
  -moz-opacity: 1;
}
.l_header #wrapper .title {
  position: relative;
  color: var(--color-text);
  padding-left: 24px;
  max-height: 64px;
}
.l_header #wrapper .nav-main .title {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex-shrink: 0;
  line-height: 64px;
  padding: 0 24px;
  font-size: 1.25rem;
  font-family: UbuntuMono, "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Helvetica, monospace;
}
.l_header #wrapper .nav-main .title img {
  height: 64px;
}
.l_header .nav-sub {
  max-width: 1080px;
  margin: auto;
}
.l_header .nav-sub .title {
  font-weight: bold;
  font-family: UbuntuMono, "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Menlo, Monaco, monospace, sans-serif;
  line-height: 1.2;
  max-height: 64px;
  white-space: normal;
  flex-shrink: 1;
}
.l_header .switcher {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
  line-height: 64px;
  align-items: center;
}
.l_header .switcher .s-toc {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
}
@media screen and (max-width: 768px) {
  .l_header .switcher .s-toc {
    display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
    display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
    display: -ms-flexbox /* TWEENER - IE 10 */;
    display: -webkit-flex /* NEW - Chrome */;
    display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
    display: flex;
  }
}
.l_header .switcher >li {
  height: 48px;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
  margin: 2px;
}
@media screen and (max-width: 500px) {
  .l_header .switcher >li {
    margin: 0 1px;
    height: 48px;
  }
}
.l_header .switcher >li >a {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  justify-content: center;
  -webkit-justify-content: center;
  -khtml-justify-content: center;
  -moz-justify-content: center;
  -o-justify-content: center;
  -ms-justify-content: center;
  align-items: center;
  width: 48px;
  height: 48px;
  padding: 0.85em 1.1em;
  border-radius: 100px;
  -webkit-border-radius: 100px;
  border: none;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
  color: #3dd9b6;
}
.l_header .switcher >li >a:hover {
  border: none;
}
.l_header .switcher >li >a.active,
.l_header .switcher >li >a:active {
  border: none;
  background: var(--color-site-bg);
}
@media screen and (max-width: 500px) {
  .l_header .switcher >li >a {
    width: 36px;
    height: 48px;
  }
}
.l_header .nav-sub .switcher {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
}
.l_header .m_search {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  height: 64px;
  width: 240px;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
@media screen and (max-width: 1024px) {
  .l_header .m_search {
    width: 44px;
    min-width: 44px;
  }
  .l_header .m_search input::placeholder {
    opacity: 0;
    -webkit-opacity: 0;
    -moz-opacity: 0;
  }
  .l_header .m_search:hover {
    width: 240px;
  }
  .l_header .m_search:hover input::placeholder {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@media screen and (min-width: 500px) {
  .l_header .m_search:hover .input {
    width: 100%;
  }
  .l_header .m_search:hover .input::placeholder {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
@media screen and (max-width: 500px) {
  .l_header .m_search {
    min-width: 0;
  }
  .l_header .m_search input::placeholder {
    opacity: 1;
    -webkit-opacity: 1;
    -moz-opacity: 1;
  }
}
.l_header .m_search .form {
  position: relative;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  width: 100%;
  align-items: center;
}
.l_header .m_search .icon {
  position: absolute;
  width: 36px;
  left: 5px;
  color: var(--color-meta);
}
@media screen and (max-width: 500px) {
  .l_header .m_search .icon {
    display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
    display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
    display: none;
  }
}
.l_header .m_search .input {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  padding-top: 8px;
  padding-bottom: 8px;
  line-height: 1.3;
  width: 100%;
  color: var(--color-text);
  background: #fafafa;
  box-shadow: none;
  -webkit-box-shadow: none;
  box-sizing: border-box;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  padding-left: 40px;
  font-size: 0.875rem;
  border-radius: 8px;
  -webkit-border-radius: 8px;
  border: none;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
@media screen and (min-width: 500px) {
  .l_header .m_search .input:focus {
    box-shadow: 0 4px 8px 0px rgba(0,0,0,0.1);
    -webkit-box-shadow: 0 4px 8px 0px rgba(0,0,0,0.1);
  }
}
@media screen and (max-width: 500px) {
  .l_header .m_search .input {
    background: var(--color-block);
    padding-left: 8px;
    border: none;
  }
  .l_header .m_search .input:hover,
  .l_header .m_search .input:focus {
    border: none;
  }
}
@media (max-width: 500px) {
  .l_header .m_search {
    left: 0;
    width: 0;
    overflow: hidden;
    position: absolute;
    background: #fff;
    transition: all 0.28s ease;
    -webkit-transition: all 0.28s ease;
    -khtml-transition: all 0.28s ease;
    -moz-transition: all 0.28s ease;
    -o-transition: all 0.28s ease;
    -ms-transition: all 0.28s ease;
  }
  .l_header .m_search .input {
    border-radius: 32px;
    -webkit-border-radius: 32px;
    margin-left: 16px;
    padding-left: 16px;
  }
  .l_header.z_search-open .m_search {
    width: 100%;
  }
  .l_header.z_search-open .m_search .input {
    width: calc(100% - 120px);
  }
}
ul.m-pc >li>a {
  color: inherit;
  border-bottom: 2px solid transparent;
}
ul.m-pc >li>a:active,
ul.m-pc >li>a.active {
  border-bottom: 2px solid #3dd9b6;
}
ul.m-pc li:hover >ul.list-v,
ul.list-v li:hover >ul.list-v {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
}
ul.nav-list-h {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: -ms-flexbox /* TWEENER - IE 10 */;
  display: -webkit-flex /* NEW - Chrome */;
  display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
  display: flex;
  align-items: stretch;
}
ul.nav-list-h>li {
  position: relative;
  justify-content: center;
  -webkit-justify-content: center;
  -khtml-justify-content: center;
  -moz-justify-content: center;
  -o-justify-content: center;
  -ms-justify-content: center;
  height: 100%;
  line-height: 2.4;
  border-radius: 4px;
  -webkit-border-radius: 4px;
}
ul.nav-list-h>li >a {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-weight: 600;
}
ul.list-v {
  z-index: 1;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
  position: absolute;
  background: var(--color-card);
  box-shadow: 0 2px 4px 0px rgba(0,0,0,0.08), 0 4px 8px 0px rgba(0,0,0,0.08), 0 8px 16px 0px rgba(0,0,0,0.08);
  -webkit-box-shadow: 0 2px 4px 0px rgba(0,0,0,0.08), 0 4px 8px 0px rgba(0,0,0,0.08), 0 8px 16px 0px rgba(0,0,0,0.08);
  margin-top: -6px;
  border-radius: 4px;
  -webkit-border-radius: 4px;
  padding: 8px 0;
}
ul.list-v.show {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
}
ul.list-v hr {
  margin-top: 8px;
  margin-bottom: 8px;
}
ul.list-v >li {
  white-space: nowrap;
  word-break: keep-all;
}
ul.list-v >li.header {
  font-size: 0.78125rem;
  font-weight: bold;
  line-height: 2em;
  color: var(--color-meta);
  margin: 8px 16px 4px;
}
ul.list-v >li.header i {
  margin-right: 8px;
}
ul.list-v >li ul {
  margin-left: 0;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
  margin-top: -40px;
}
ul.list-v .aplayer-container {
  min-height: 64px;
  padding: 6px 16px;
}
ul.list-v >li>a {
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  color: var(--color-list);
  font-size: 0.875rem;
  font-weight: bold;
  line-height: 36px;
  padding: 0 20px 0 16px;
  text-overflow: ellipsis;
  margin: 0 4px;
  border-radius: 4px;
  -webkit-border-radius: 4px;
}
@media screen and (max-width: 1024px) {
  ul.list-v >li>a {
    line-height: 40px;
  }
}
ul.list-v >li>a >i {
  margin-right: 8px;
}
ul.list-v >li>a:active,
ul.list-v >li>a.active {
  color: var(--color-list-hl);
}
ul.list-v >li>a:hover {
  color: var(--color-list-hl);
  background: var(--color-site-bg);
}
.l_header .menu >ul>li>a {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: block;
  padding: 0 8px;
}
.l_header .menu >ul>li>a >i {
  margin-right: 4px;
}
.l_header ul.nav-list-h>li {
  color: var(--color-list);
  line-height: 64px;
}
.l_header ul.nav-list-h>li >a {
  max-height: 64px;
  overflow: hidden;
  color: inherit;
}
.l_header ul.nav-list-h>li >a:active,
.l_header ul.nav-list-h>li >a.active {
  color: #3dd9b6;
}
.l_header ul.nav-list-h>li:hover>a {
  color: var(--color-list-hl);
}
.l_header ul.nav-list-h>li i.music {
  animation: rotate-effect 1.5s linear infinite;
  -webkit-animation: rotate-effect 1.5s linear infinite;
  -khtml-animation: rotate-effect 1.5s linear infinite;
  -moz-animation: rotate-effect 1.5s linear infinite;
  -o-animation: rotate-effect 1.5s linear infinite;
  -ms-animation: rotate-effect 1.5s linear infinite;
}
@-moz-keyframes rotate-effect {
  0% {
    transform: rotate(0);
    -webkit-transform: rotate(0);
    -khtml-transform: rotate(0);
    -moz-transform: rotate(0);
    -o-transform: rotate(0);
    -ms-transform: rotate(0);
  }
  25% {
    transform: rotate(90deg);
    -webkit-transform: rotate(90deg);
    -khtml-transform: rotate(90deg);
    -moz-transform: rotate(90deg);
    -o-transform: rotate(90deg);
    -ms-transform: rotate(90deg);
  }
  50% {
    transform: rotate(180deg);
    -webkit-transform: rotate(180deg);
    -khtml-transform: rotate(180deg);
    -moz-transform: rotate(180deg);
    -o-transform: rotate(180deg);
    -ms-transform: rotate(180deg);
  }
  75% {
    transform: rotate(270deg);
    -webkit-transform: rotate(270deg);
    -khtml-transform: rotate(270deg);
    -moz-transform: rotate(270deg);
    -o-transform: rotate(270deg);
    -ms-transform: rotate(270deg);
  }
  100% {
    transform: rotate(360deg);
    -webkit-transform: rotate(360deg);
    -khtml-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
  }
}
@-webkit-keyframes rotate-effect {
  0% {
    transform: rotate(0);
    -webkit-transform: rotate(0);
    -khtml-transform: rotate(0);
    -moz-transform: rotate(0);
    -o-transform: rotate(0);
    -ms-transform: rotate(0);
  }
  25% {
    transform: rotate(90deg);
    -webkit-transform: rotate(90deg);
    -khtml-transform: rotate(90deg);
    -moz-transform: rotate(90deg);
    -o-transform: rotate(90deg);
    -ms-transform: rotate(90deg);
  }
  50% {
    transform: rotate(180deg);
    -webkit-transform: rotate(180deg);
    -khtml-transform: rotate(180deg);
    -moz-transform: rotate(180deg);
    -o-transform: rotate(180deg);
    -ms-transform: rotate(180deg);
  }
  75% {
    transform: rotate(270deg);
    -webkit-transform: rotate(270deg);
    -khtml-transform: rotate(270deg);
    -moz-transform: rotate(270deg);
    -o-transform: rotate(270deg);
    -ms-transform: rotate(270deg);
  }
  100% {
    transform: rotate(360deg);
    -webkit-transform: rotate(360deg);
    -khtml-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
  }
}
@-o-keyframes rotate-effect {
  0% {
    transform: rotate(0);
    -webkit-transform: rotate(0);
    -khtml-transform: rotate(0);
    -moz-transform: rotate(0);
    -o-transform: rotate(0);
    -ms-transform: rotate(0);
  }
  25% {
    transform: rotate(90deg);
    -webkit-transform: rotate(90deg);
    -khtml-transform: rotate(90deg);
    -moz-transform: rotate(90deg);
    -o-transform: rotate(90deg);
    -ms-transform: rotate(90deg);
  }
  50% {
    transform: rotate(180deg);
    -webkit-transform: rotate(180deg);
    -khtml-transform: rotate(180deg);
    -moz-transform: rotate(180deg);
    -o-transform: rotate(180deg);
    -ms-transform: rotate(180deg);
  }
  75% {
    transform: rotate(270deg);
    -webkit-transform: rotate(270deg);
    -khtml-transform: rotate(270deg);
    -moz-transform: rotate(270deg);
    -o-transform: rotate(270deg);
    -ms-transform: rotate(270deg);
  }
  100% {
    transform: rotate(360deg);
    -webkit-transform: rotate(360deg);
    -khtml-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
  }
}
@keyframes rotate-effect {
  0% {
    transform: rotate(0);
    -webkit-transform: rotate(0);
    -khtml-transform: rotate(0);
    -moz-transform: rotate(0);
    -o-transform: rotate(0);
    -ms-transform: rotate(0);
  }
  25% {
    transform: rotate(90deg);
    -webkit-transform: rotate(90deg);
    -khtml-transform: rotate(90deg);
    -moz-transform: rotate(90deg);
    -o-transform: rotate(90deg);
    -ms-transform: rotate(90deg);
  }
  50% {
    transform: rotate(180deg);
    -webkit-transform: rotate(180deg);
    -khtml-transform: rotate(180deg);
    -moz-transform: rotate(180deg);
    -o-transform: rotate(180deg);
    -ms-transform: rotate(180deg);
  }
  75% {
    transform: rotate(270deg);
    -webkit-transform: rotate(270deg);
    -khtml-transform: rotate(270deg);
    -moz-transform: rotate(270deg);
    -o-transform: rotate(270deg);
    -ms-transform: rotate(270deg);
  }
  100% {
    transform: rotate(360deg);
    -webkit-transform: rotate(360deg);
    -khtml-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
  }
}
.menu-phone li ul.list-v {
  right: calc(100% - 0.5 * 16px);
}
.menu-phone li ul.list-v ul {
  right: calc(100% - 0.5 * 16px);
}
#wrapper {
  max-width: 1080px;
  margin: auto;
}
@media screen and (min-width: 2048px) {
  #wrapper {
    max-width: 55vw;
  }
}
#wrapper .menu {
  -webkit-box-flex: 1;
  -moz-box-flex: 1;
  -webkit-flex: 1 1;
  -ms-flex: 1 1;
  flex: 1 1;
  margin: 0 16px 0 0;
}
#wrapper .menu .list-v ul {
  left: calc(100% - 0.5 * 16px);
}
.menu-phone {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
  margin-top: 16px;
  right: 8px;
  transition: all 0.28s ease;
  -webkit-transition: all 0.28s ease;
  -khtml-transition: all 0.28s ease;
  -moz-transition: all 0.28s ease;
  -o-transition: all 0.28s ease;
  -ms-transition: all 0.28s ease;
}
.menu-phone ul {
  right: calc(100% - 0.5 * 16px);
}
@media screen and (max-width: 500px) {
  .menu-phone {
    display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
    display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
    display: block;
  }
}
.l_header {
  max-width: 65vw;
  left: calc((100% - 65vw) * 0.5);
  border-bottom-left-radius: 8px;
  border-bottom-right-radius: 8px;
}
@media screen and (max-width: 2048px) {
  .l_header {
    max-width: 1112px;
    left: calc((100% - 1112px) * 0.5);
  }
}
@media screen and (max-width: 1112px) {
  .l_header {
    left: 0;
    border-radius: 0;
    -webkit-border-radius: 0;
    max-width: 100%;
  }
}
@media screen and (max-width: 500px) {
  .l_header .container {
    margin-left: 0;
    margin-right: 0;
  }
  .l_header #wrapper .nav-main .title {
    padding-left: 16px;
    padding-right: 16px;
  }
  .l_header #wrapper .nav-sub {
    width: 100%;
  }
  .l_header #wrapper .nav-sub .title {
    overflow-y: scroll;
    margin-top: 2px;
    padding: 8px 16px;
  }
  .l_header #wrapper .switcher {
    display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
    display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
    display: -ms-flexbox /* TWEENER - IE 10 */;
    display: -webkit-flex /* NEW - Chrome */;
    display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */;
    display: flex;
    margin-right: 8px;
  }
  .l_header .menu {
    display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
    display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
    display: none;
  }
}
@media screen and (max-width: 500px) {
  .list-v li {
    max-width: 270px;
  }
}
#u-search {
  display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */;
  display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */;
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  padding: 60px 20px;
  z-index: 1001;
}
@media screen and (max-width: 680px) {
  #u-search {
    padding: 0px;
  }
}
@media screen and (prefers-color-scheme: dark) and (max-width: 500px) {
  .l_header .m_search {
    background: var(--color-site-bg) !important;
  }
}

  </style>
  <link rel="stylesheet" href="/css/style.css" media="print" onload="this.media='all';this.onload=null">
  <noscript><link rel="stylesheet" href="/css/style.css"></noscript>
    <script>
      let userColorScheme=localStorage.getItem("color-scheme")
      if(userColorScheme){
        document.documentElement.setAttribute("color-scheme", userColorScheme);
      }
    </script>
  
<script>
if (/*@cc_on!@*/false || (!!window.MSInputMethodContext && !!document.documentMode))
    document.write(
	'<style>'+
		'html{'+
			'overflow-x: hidden !important;'+
			'overflow-y: hidden !important;'+
		'}'+
		'.kill-ie{'+
			'text-align:center;'+
			'height: 100%;'+
			'margin-top: 15%;'+
			'margin-bottom: 5500%;'+
		'}'+
    '.kill-t{'+
      'font-size: 2rem;'+
    '}'+
    '.kill-c{'+
      'font-size: 1.2rem;'+
    '}'+
		'#l_header,#l_body{'+
			'display: none;'+
		'}'+
	'</style>'+
    '<div class="kill-ie">'+
        `<span class="kill-t"><b>抱歉，您的浏览器无法访问本站</b></span><br/>`+
        `<span class="kill-c">微软已经于2016年终止了对 Internet Explorer (IE) 10 及更早版本的支持，<br/>继续使用存在极大的安全隐患，请使用当代主流的浏览器进行访问。</span><br/>`+
        `<a target="_blank" rel="noopener" href="https://blogs.windows.com/windowsexperience/2021/05/19/the-future-of-internet-explorer-on-windows-10-is-in-microsoft-edge/"><strong>了解详情 ></strong></a>`+
    '</div>');
</script>


<noscript>
	<style>
		html{
			overflow-x: hidden !important;
			overflow-y: hidden !important;
		}
		.kill-noscript{
			text-align:center;
			height: 100%;
			margin-top: 15%;
			margin-bottom: 5500%;
		}
    .kill-t{
      font-size: 2rem;
    }
    .kill-c{
      font-size: 1.2rem;
    }
		#l_header,#l_body{
			display: none;
		}
	</style>
    <div class="kill-noscript">
        <span class="kill-t"><b>抱歉，您的浏览器无法访问本站</b></span><br/>
        <span class="kill-c">本页面需要浏览器支持（启用）JavaScript</span><br/>
        <a target="_blank" rel="noopener" href="https://www.baidu.com/s?wd=启用JavaScript"><strong>了解详情 ></strong></a>
    </div>
</noscript>


  <script>
  /************这个文件存放不需要重载的全局变量和全局函数*********/
  window.volantis = {}; // volantis 全局变量
  volantis.debug = "false"; // 调试模式
  volantis.dom = {}; // 页面Dom see: /source/js/app.js etc.

  volantis.GLOBAL_CONFIG ={
    debug: false,
    cdn: {"js":{"app":"/js/app.js","parallax":"/js/plugins/parallax.js","rightMenu":"/js/plugins/rightMenu.js","rightMenus":"/js/plugins/rightMenus.js","sites":"/js/plugins/tags/sites.js","friends":"/js/plugins/tags/friends.js","contributors":"/js/plugins/tags/contributors.js","search":"/js/search/hexo.js"},"css":{"style":"/css/style.css"}},
    default: {"avatar":"images/userphoto/userphoto02.png","link":"https://unpkg.com/volantis-static@0.0.1654736714924/media/placeholder/link/8f277b4ee0ecd.svg","cover":"https://unpkg.com/volantis-static@0.0.1654736714924/media/placeholder/cover/76b86c0226ffd.svg","image":"https://unpkg.com/volantis-static@0.0.1654736714924/media/placeholder/image/2659360.svg"},
    lastupdate: new Date(1714981444297),
    sidebar: {
      for_page: ["blogger","category","guide","tagcloud","webinfo"],
      for_post: ["toc","webinfo"],
      webinfo: {
        lastupd: {
          enable: true,
          friendlyShow: true
        },
        runtime: {
          data: "2023/10/20",
          unit: "天"
        }
      }
    },
    plugins: {
      message: {"enable":true,"css":"https://unpkg.com/volantis-static@0.0.1654736714924/libs/izitoast/dist/css/iziToast.min.css","js":"https://unpkg.com/volantis-static@0.0.1654736714924/libs/izitoast/dist/js/iziToast.min.js","icon":{"default":"fa-light fa-info-circle light-blue","quection":"fa-light fa-question-circle light-blue"},"time":{"default":5000,"quection":20000},"position":"topRight","transitionIn":"bounceInLeft","transitionOut":"fadeOutRight","titleColor":"var(--color-text)","messageColor":"var(--color-text)","backgroundColor":"var(--color-card)","zindex":2147483647,"copyright":{"enable":false,"title":"知识共享许可协议","message":"请遵守 CC BY-NC-SA 4.0 协议。","icon":"fa-brands fa-creative-commons light-blue"},"aplayer":{"enable":false,"play":"fa-light fa-play light-blue","pause":"fa-light fa-pause light-blue","error":"fa-light fa-exclamation-square red"},"rightmenu":{"enable":true,"notice":true}},
      fancybox: {"css":"https://unpkg.com/volantis-static@0.0.1654736714924/libs/@fancyapps/ui/dist/fancybox.css","js":"https://unpkg.com/volantis-static@0.0.1654736714924/libs/@fancyapps/ui/dist/fancybox.umd.js"},
      
      
      
      rightmenus: {"enable":true,"order":["plugins.navigation","hr","plugins.inputBox","plugins.seletctText","plugins.elementCheck","plugins.elementImage","hr","menus.prevNext","hr","hr","menus.darkMode","hr","plugins.articlePage","hr"],"options":{"iconPrefix":"fa-duotone PETERRIVE","articleShowLink":true,"musicAlwaysShow":true},"plugins":{"navigation":[{"id":"left","name":"转到上一页","icon":"fa-duotone fa-arrow-left PETERRIVE","event":"history.back()","group":"navigation"},{"id":"right","name":"转到下一页","icon":"fa-duotone fa-arrow-right PETERRIVE","event":"history.forward()","group":"navigation"},{"id":"redo","name":"刷新当前页面","icon":"fa-duotone fa-redo PETERRIVE","event":"window.location.reload()","group":"navigation"},{"id":"up","name":"回到顶部","icon":"fa-duotone fa-arrow-up PETERRIVE","event":"VolantisApp.scrolltoElement(volantis.dom.bodyAnchor)","group":"navigation"}],"inputBox":[{"id":"copyPaste","name":"粘贴文本","icon":"fa-duotone PETERRIVE fa-paste","event":"copyPaste","group":"inputBox"},{"id":"copyAll","name":"全选文本","icon":"fa-duotone PETERRIVE fa-object-ungroup","event":"copyAll","group":"inputBox"},{"id":"copyCut","name":"剪切文本","icon":"fa-duotone PETERRIVE fa-cut","event":"copyCut","group":"inputBox"}],"seletctText":[{"id":"copyText","name":"复制文本","icon":"fa-duotone PETERRIVE fa-copy","event":"copyText","group":"seletctText"},{"id":"searchWord","name":"站内搜索","icon":"fa-duotone PETERRIVE fa-search","event":"OpenSearch(__text__)","group":"seletctText"},{"id":"bingSearch","name":"必应搜索","icon":"fa-duotone PETERRIVE fa-search","event":"window.open(`https://cn.bing.com/search?q=${__text__}`)","group":"seletctText"}],"elementCheck":[{"id":"openTab","name":"新标签页打开","icon":"fa-duotone PETERRIVE fa-external-link-square-alt","event":"window.open(__link__)","group":"elementCheck"},{"id":"copyLink","name":"复制链接地址","icon":"fa-duotone PETERRIVE fa-link","event":"copyLink","group":"elementCheck"}],"elementImage":[{"id":"copyImg","name":"复制图片","icon":"fa-duotone PETERRIVE fa-image","event":"copyImg","group":"elementImage"},{"id":"googleImg","name":"谷歌识图","icon":"fa-duotone PETERRIVE fa-images","event":"window.open(`https://www.google.com/searchbyimage?image_url=${__link__}`)","group":"elementImage"}],"articlePage":[{"id":"printMode","name":"打印页面","icon":"fa-duotone fa-print TURQUOISE","event":"printMode","group":"articlePage"},{"id":"readMode","name":"阅读模式","icon":"fa-duotone fa-book-open EMERALD","event":"readMode","group":"articlePage"}]},"menus":{"link":[{"id":"help","name":"常见问题","icon":"fa-solid fa-question","link":"https://volantis.js.org/faqs/","group":"link"},{"id":"examples","name":"示例博客","icon":"fa-solid fa-rss","link":"https://volantis.js.org/examples/","group":"link"},{"id":"contributors","name":"加入社区","icon":"fa-solid fa-fan","link":"https://volantis.js.org/contributors/","group":"link"},"hr",{"id":"source_docs","name":"本站源码","icon":"fa-solid fa-code-branch","link":"https://github.com/volantis-x/volantis-docs/","group":"link"},{"id":"source_theme","name":"主题源码","icon":"fa-solid fa-code-branch","link":"https://github.com/volantis-x/hexo-theme-volantis/","group":"link"}],"darkMode":[{"id":"darkMode","name":"暗黑模式","icon":"fa-duotone fa-eclipse-alt WISTERIA","event":"volantis.dark.toggle()","group":"darkMode"}],"links":[{"id":"help","name":"常见问题","icon":"fa-duotone fa-question EMERALD","link":"/faqs/","group":"link"},{"id":"examples","name":"示例博客","icon":"fa-duotone fa-rss PETERRIVE","link":"/examples/","group":"link"},{"id":"contributors","name":"加入社区","icon":"fa-duotone fa-fan fa-spin AMETHYST","link":"/contributors/","group":"link"},"hr",{"id":"source_docs","name":"本站源码","icon":"fa-duotone fa-code-branch WETASPHALT","link":"https://github.com/volantis-x/volantis-docs/","group":"link"},{"id":"source_theme","name":"主题源码","icon":"fa-duotone fa-code-branch CONCRETE","link":"https://github.com/volantis-x/hexo-theme-volantis/","group":"link"}],"prevNext":[{"id":"prev","name":"查看上一篇","icon":"fa-duotone fa-angles-left PETERRIVE","event":"volantis.rightmenu.jump('prev')","group":"prevNext"},{"id":"next","name":"查看下一篇","icon":"fa-duotone fa-angles-right PETERRIVE","event":"volantis.rightmenu.jump('next')","group":"prevNext"}]}}
      
    }
  }

  /******************** volantis.EventListener ********************************/
  // 事件监听器 see: /source/js/app.js
  volantis.EventListener = {}
  // 这里存放pjax切换页面时将被移除的事件监听器
  volantis.EventListener.list = []
  //构造方法
  function volantisEventListener(type, f, ele) {
    this.type = type
    this.f = f
    this.ele = ele
  }
  // 移除事件监听器
  volantis.EventListener.remove = () => {
    volantis.EventListener.list.forEach(function (i) {
      i.ele.removeEventListener(i.type, i.f, false)
    })
    volantis.EventListener.list = []
  }
  /******************** volantis.dom.$ ********************************/
  // 注：这里没有选择器，也没有forEach一次只处理一个dom，这里重新封装主题常用的dom方法，返回的是dom对象，对象包含了以下方法，同时保留dom的原生API
  function volantisDom(ele) {
    if (!ele) ele = document.createElement("div")
    this.ele = ele;
    // ==============================================================
    this.ele.find = (c) => {
      let q = this.ele.querySelector(c)
      if (q)
        return new volantisDom(q)
    }
    // ==============================================================
    this.ele.hasClass = (c) => {
      return this.ele.className.match(new RegExp('(\\s|^)' + c + '(\\s|$)'));
    }
    this.ele.addClass = (c) => {
      this.ele.classList.add(c);
      return this.ele
    }
    this.ele.removeClass = (c) => {
      this.ele.classList.remove(c);
      return this.ele
    }
    this.ele.toggleClass = (c) => {
      if (this.ele.hasClass(c)) {
        this.ele.removeClass(c)
      } else {
        this.ele.addClass(c)
      }
      return this.ele
    }
    // ==============================================================
    // 参数 r 为 true 表示pjax切换页面时事件监听器将被移除，false不移除
    this.ele.on = (c, f, r = 1) => {
      this.ele.addEventListener(c, f, false)
      if (r) {
        volantis.EventListener.list.push(new volantisEventListener(c, f, this.ele))
      }
      return this.ele
    }
    this.ele.click = (f, r) => {
      this.ele.on("click", f, r)
      return this.ele
    }
    this.ele.scroll = (f, r) => {
      this.ele.on("scroll", f, r)
      return this.ele
    }
    // ==============================================================
    this.ele.html = (c) => {
      // if(c=== undefined){
      //   return this.ele.innerHTML
      // }else{
      this.ele.innerHTML = c
      return this.ele
      // }
    }
    // ==============================================================
    this.ele.hide = (c) => {
      this.ele.style.display = "none"
      return this.ele
    }
    this.ele.show = (c) => {
      this.ele.style.display = "block"
      return this.ele
    }
    // ==============================================================
    return this.ele
  }
  volantis.dom.$ = (ele) => {
    return !!ele ? new volantisDom(ele) : null;
  }
  /******************** RunItem ********************************/
  function RunItem() {
    this.list = []; // 存放回调函数
    this.start = () => {
      for (var i = 0; i < this.list.length; i++) {
        this.list[i].run();
      }
    };
    this.push = (fn, name, setRequestAnimationFrame = true) => {
      let myfn = fn
      if (setRequestAnimationFrame) {
        myfn = ()=>{
          volantis.requestAnimationFrame(fn)
        }
      }
      var f = new Item(myfn, name);
      this.list.push(f);
    };
    this.remove = (name) =>{
      for (let index = 0; index < this.list.length; index++) {
        const e = this.list[index];
        if (e.name == name) {
          this.list.splice(index,1);
        }
      }
    }
    // 构造一个可以run的对象
    function Item(fn, name) {
      // 函数名称
      this.name = name || fn.name;
      // run方法
      this.run = () => {
        try {
          fn()
        } catch (error) {
          console.log(error);
        }
      };
    }
  }
  /******************** Pjax ********************************/
  // /layout/_plugins/pjax/index.ejs
  // volantis.pjax.send(callBack[,"callBackName"]) 传入pjax:send回调函数
  // volantis.pjax.push(callBack[,"callBackName"]) 传入pjax:complete回调函数
  // volantis.pjax.error(callBack[,"callBackName"]) 传入pjax:error回调函数
  volantis.pjax = {};
  volantis.pjax.method = {
    complete: new RunItem(),
    error: new RunItem(),
    send: new RunItem(),
  };
  volantis.pjax = Object.assign(volantis.pjax, {
    push: volantis.pjax.method.complete.push,
    error: volantis.pjax.method.error.push,
    send: volantis.pjax.method.send.push,
  });
  /******************** RightMenu ********************************/
  // volantis.rightmenu.handle(callBack[,"callBackName"]) 外部菜单项控制
  // 可在 volantis.mouseEvent 处获取右键事件
  volantis.rightmenu = {};
  volantis.rightmenu.method = {
    handle: new RunItem(),
  }
  volantis.rightmenu = Object.assign(volantis.rightmenu, {
    handle: volantis.rightmenu.method.handle.push,
  });
  /********************  Dark Mode  ********************************/
  // /layout/_partial/scripts/darkmode.ejs
  // volantis.dark.mode 当前模式 dark or light
  // volantis.dark.toggle() 暗黑模式触发器
  // volantis.dark.push(callBack[,"callBackName"]) 传入触发器回调函数
  volantis.dark = {};
  volantis.dark.method = {
    toggle: new RunItem(),
  };
  volantis.dark = Object.assign(volantis.dark, {
    push: volantis.dark.method.toggle.push,
  });
  /********************  Message  ********************************/
  // VolantisApp.message
  /********************  isMobile  ********************************/
  // /source/js/app.js
  // volantis.isMobile
  // volantis.isMobileOld
  /********************脚本动态加载函数********************************/
  // volantis.js(src, cb)  cb 可以传入onload回调函数 或者 JSON对象 例如: volantis.js("src", ()=>{}) 或 volantis.js("src", {defer:true,onload:()=>{}})
  // volantis.css(src)

  // 返回Promise对象，如下方法同步加载资源，这利于处理文件资源之间的依赖关系，例如：APlayer 需要在 MetingJS 之前加载
  // (async () => {
  //     await volantis.js("...theme.plugins.aplayer.js.aplayer...")
  //     await volantis.js("...theme.plugins.aplayer.js.meting...")
  // })();

  // 已经加入了setTimeout
  volantis.js = (src, cb) => {
    return new Promise(resolve => {
      setTimeout(function () {
        var HEAD = document.getElementsByTagName("head")[0] || document.documentElement;
        var script = document.createElement("script");
        script.setAttribute("type", "text/javascript");
        if (cb) {
          if (JSON.stringify(cb)) {
            for (let p in cb) {
              if (p == "onload") {
                script[p] = () => {
                  cb[p]()
                  resolve()
                }
              } else {
                script[p] = cb[p]
                script.onload = resolve
              }
            }
          } else {
            script.onload = () => {
              cb()
              resolve()
            };
          }
        } else {
          script.onload = resolve
        }
        script.setAttribute("src", src);
        HEAD.appendChild(script);
      });
    });
  }
  volantis.css = (src) => {
    return new Promise(resolve => {
      setTimeout(function () {
        var link = document.createElement('link');
        link.rel = "stylesheet";
        link.href = src;
        link.onload = resolve;
        document.getElementsByTagName("head")[0].appendChild(link);
      });
    });
  }
  /********************按需加载的插件********************************/
  // volantis.import.jQuery().then(()=>{})
  volantis.import = {
    jQuery: () => {
      if (typeof jQuery == "undefined") {
        return volantis.js("https://unpkg.com/volantis-static@0.0.1654736714924/libs/jquery/dist/jquery.min.js")
      } else {
        return new Promise(resolve => {
          resolve()
        });
      }
    }
  }
  /********************** requestAnimationFrame ********************************/
  // 1、requestAnimationFrame 会把每一帧中的所有 DOM 操作集中起来，在一次重绘或回流中就完成，并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率，一般来说，这个频率为每秒60帧。
  // 2、在隐藏或不可见的元素中，requestAnimationFrame 将不会进行重绘或回流，这当然就意味着更少的的 cpu，gpu 和内存使用量。
  volantis.requestAnimationFrame = (fn)=>{
    if (!window.requestAnimationFrame) {
      window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame;
    }
    window.requestAnimationFrame(fn)
  }
  /************************ layoutHelper *****************************************/
  volantis.layoutHelper = (helper, html, opt)=>{
    opt = Object.assign({clean:false, pjax:true}, opt)
    function myhelper(helper, html, clean) {
      volantis.tempDiv = document.createElement("div");
      volantis.tempDiv.innerHTML = html;
      let layoutHelper = document.querySelector("#layoutHelper-"+helper)
      if (layoutHelper) {
        if (clean) {
          layoutHelper.innerHTML = ""
        }
        layoutHelper.append(volantis.tempDiv);
      }
    }
    myhelper(helper, html, opt.clean)
    if (opt.pjax) {
      volantis.pjax.push(()=>{
        myhelper(helper, html, opt.clean)
      },"layoutHelper-"+helper)
    }
  }
  /****************************** 滚动事件处理 ****************************************/
  volantis.scroll = {
    engine: new RunItem(),
    unengine: new RunItem(),
  };
  volantis.scroll = Object.assign(volantis.scroll, {
    push: volantis.scroll.engine.push,
  });
  // 滚动条距离顶部的距离
  volantis.scroll.getScrollTop = () =>{
    let scrollPos;
    if (window.pageYOffset) {
      scrollPos = window.pageYOffset;
    } else if (document.compatMode && document.compatMode != 'BackCompat') {
      scrollPos = document.documentElement.scrollTop;
    } else if (document.body) {
      scrollPos = document.body.scrollTop;
    }
    return scrollPos;
  }
  // 使用 requestAnimationFrame 处理滚动事件
  // `volantis.scroll.del` 中存储了一个数值, 该数值检测一定时间间隔内滚动条滚动的位移, 数值的检测频率是浏览器的刷新频率. 数值为正数时, 表示向下滚动. 数值为负数时, 表示向上滚动.
  volantis.scroll.handleScrollEvents = () => {
    volantis.scroll.lastScrollTop = volantis.scroll.getScrollTop()
    function loop() {
      const scrollTop = volantis.scroll.getScrollTop();
      if (volantis.scroll.lastScrollTop !== scrollTop) {
        volantis.scroll.del = scrollTop - volantis.scroll.lastScrollTop;
        volantis.scroll.lastScrollTop = scrollTop;
        // if (volantis.scroll.del > 0) {
        //   console.log("向下滚动");
        // } else {
        //   console.log("向上滚动");
        // }
        // 注销过期的unengine未滚动事件
        volantis.scroll.unengine.list=[]
        volantis.scroll.engine.start();
      }else{
        volantis.scroll.unengine.start();
      }
      volantis.requestAnimationFrame(loop)
    }
    volantis.requestAnimationFrame(loop)
  }
  volantis.scroll.handleScrollEvents()
  volantis.scroll.ele = null;
  // 触发页面滚动至目标元素位置
  volantis.scroll.to = (ele, option = {}) => {
    if (!ele) return;
    volantis.scroll.ele = ele;
    // 默认配置
    opt = {
      top: ele.getBoundingClientRect().top + document.documentElement.scrollTop,
      behavior: "smooth"
    }
    // 定义配置
    if ("top" in option) {
      opt.top = option.top
    }
    if ("behavior" in option) {
      opt.behavior = option.behavior
    }
    if ("addTop" in option) {
      opt.top += option.addTop
    }
    if (!("observerDic" in option)) {
      option.observerDic = 100
    }
    // 滚动
    window.scrollTo(opt);
    // 监视器
    // 监视并矫正元素滚动到指定位置
    // 用于处理 lazyload 引起的 cls 导致的定位失败问题
    // option.observer = false
    if (option.observer) {
      setTimeout(() => {
        if (volantis.scroll.ele != ele) {
          return
        }
        volantis.scroll.unengine.push(() => {
          let me = ele.getBoundingClientRect().top
          if(!(me >= -option.observerDic && me <= option.observerDic)){
            volantis.scroll.to(ele, option)
          }
          volantis.scroll.unengine.remove("unengineObserver")
        },"unengineObserver")
      },1000)
    }
  }
  /********************** Content Visibility ********************************/
  // 见 source/css/first.styl 如果遇到任何问题 删除 .post-story 即可
  // 一个元素被声明 content-visibility 属性后 如果元素不在 viewport 中 浏览器不会计算其后代元素样式和属性 从而节省 Style & Layout 耗时
  // content-visibility 的副作用: 锚点失效 等等(实验初期 暂不明确), 使用此方法清除样式
  volantis.cleanContentVisibility = ()=>{
    if (document.querySelector(".post-story")) {
      console.log("cleanContentVisibility");
      document.querySelectorAll(".post-story").forEach(e=>{
        e.classList.remove("post-story")
      })
    }
  }
  /******************************************************************************/
  /******************************************************************************/
  /******************************************************************************/
  //图像加载出错时的处理
  function errorImgAvatar(img) {
    img.src = "images/userphoto/userphoto02.png";
    img.onerror = null;
  }
  function errorImgCover(img) {
    img.src = "https://unpkg.com/volantis-static@0.0.1654736714924/media/placeholder/cover/76b86c0226ffd.svg";
    img.onerror = null;
  }
  /******************************************************************************/
</script>

  <!-- import head_end begin -->
  <!-- import head_end end -->
  <!-- Custom Files headEnd begin-->
  
  <!-- Custom Files headEnd end-->
  <!-- front-matter head_end begin -->
  <!-- front-matter head_end end -->
</head>
  <body itemscope itemtype="http://schema.org/WebPage">
    <!-- import body_begin begin-->
    <!-- import body_begin end-->
    <!-- Custom Files bodyBegin begin-->
    
    <!-- Custom Files bodyBegin end-->
    <!-- front-matter body_begin begin -->
    <!-- front-matter body_begin end -->
    <header itemscope itemtype="http://schema.org/WPHeader" id="l_header" class="l_header auto blur show" style='opacity: 0' >
  <div class='container'>
  <div id='wrapper'>
    <div class='nav-sub'>
      <p class="title"></p>
      <ul class='switcher nav-list-h m-phone' id="pjax-header-nav-list">
        <li><a id="s-comment" class="fa-solid fa-comments fa-fw" target="_self"  href="/" onclick="return false;" title="comment"></a></li>
        
          <li><a id="s-toc" class="s-toc fa-solid fa-list fa-fw" target="_self"  href="/" onclick="return false;" title="toc"></a></li>
        
      </ul>
    </div>
		<div class="nav-main">
      
        
        <a class="title flat-box" target="_self" href='/'>
          
          
          
            诚实同学<sup style="color:#ff9800">Blog</sup>
          
        </a>
      

			<div class='menu navigation'>
				<ul class='nav-list-h m-pc'>
          
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/" title="首页"
                  
                  
                  
                    active-action="action-home"
                  >
                  <i class='fa-solid fa-house fa-fw'></i>首页
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/categories/" title="分类"
                  
                  
                  
                    active-action="action-categories"
                  >
                  <i class='fa-solid fa-folder-open fa-fw'></i>分类
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/tags/" title="标签"
                  
                  
                  
                    active-action="action-tags"
                  >
                  <i class='fa-solid fa-tags fa-fw'></i>标签
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/archives/" title="归档"
                  
                  
                  
                    active-action="action-archives"
                  >
                  <i class='fa-solid fa-archive fa-fw'></i>归档
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/about/" title="关于我"
                  
                  
                  
                    active-action="action-about"
                  >
                  <i class='fa-solid fa-info-circle fa-fw'></i>关于我
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box header toggle-mode-btn">
                  <i class='fa-solid fa-moon fa-fw'></i>暗黑模式
                </a>
              <li>
            
          
          
				</ul>
			</div>
      
      <div class="m_search">
        <form name="searchform" class="form u-search-form">
          <i class="icon fa-solid fa-search fa-fw"></i>
          <input type="text" class="input u-search-input" placeholder="随便逛逛..." />
        </form>
      </div>
      

			<ul class='switcher nav-list-h m-phone'>
				
					<li><a class="s-search fa-solid fa-search fa-fw" target="_self" href="/" onclick="return false;" title="search"></a></li>
				
				<li>
          <a class="s-menu fa-solid fa-bars fa-fw" target="_self" href="/" onclick="return false;" title="menu"></a>
          <ul class="menu-phone list-v navigation white-box">
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/" title="首页"
                  
                  
                  
                    active-action="action-home"
                  >
                  <i class='fa-solid fa-house fa-fw'></i>首页
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/categories/" title="分类"
                  
                  
                  
                    active-action="action-categories"
                  >
                  <i class='fa-solid fa-folder-open fa-fw'></i>分类
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/tags/" title="标签"
                  
                  
                  
                    active-action="action-tags"
                  >
                  <i class='fa-solid fa-tags fa-fw'></i>标签
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/archives/" title="归档"
                  
                  
                  
                    active-action="action-archives"
                  >
                  <i class='fa-solid fa-archive fa-fw'></i>归档
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover"
                href="/about/" title="关于我"
                  
                  
                  
                    active-action="action-about"
                  >
                  <i class='fa-solid fa-info-circle fa-fw'></i>关于我
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box header toggle-mode-btn">
                  <i class='fa-solid fa-moon fa-fw'></i>暗黑模式
                </a>
              <li>
            
          
            
          </ul>
        </li>
			</ul>

      <!-- Custom Files header begin -->
      
      <!-- Custom Files header end -->
		</div>
	</div>
  </div>
</header>

    <div id="l_body">
      <div id="l_cover">
  
    
      <!-- see: /layout/_partial/scripts/_ctrl/coverCtrl.ejs -->
      <div id="none" class='cover-wrapper post search' style="display: none;">
        
  <div id="parallax-window"></div>

<div class='cover-body'>
  <div class='top'>
    
    
      <p class="title">欢迎来到诚实同学的博客</p>
    
    
      <p class="subtitle">"Patience is key in life."</p>
    
  </div>
  <div class='bottom'>
    
      <div class="m_search">
        <form name="searchform" class="form u-search-form">
          <input type="text" class="input u-search-input" placeholder="随便逛逛..." />
          <i class="icon fa-solid fa-search fa-fw"></i>
        </form>
      </div>
    
    <div class='menu navigation'>
      <div class='list-h'>
        
          
            <a href="/"
              
              
              active-action="action-home">
              <i class='fa-solid fa-home fa-fw'></i><p>首页</p>
            </a>
          
            <a href="/categories/"
              
              
              active-action="action-categories">
              <i class='fa-solid fa-folder-open fa-fw'></i><p>分类</p>
            </a>
          
            <a href="/tags/"
              
              
              active-action="action-tags">
              <i class='fa-solid fa-tags fa-fw'></i><p>标签</p>
            </a>
          
            <a href="/archives/"
              
              
              active-action="action-archives">
              <i class='fa-solid fa-archive fa-fw'></i><p>归档</p>
            </a>
          
            <a href="/about/"
              
              
              active-action="action-about">
              <i class='fa-solid fa-info-circle fa-fw'></i><p>关于我</p>
            </a>
          
        
      </div>
    </div>
  </div>
</div>

        <div id="scroll-down" style="display: none;"><i class="fa fa-chevron-down scroll-down-effects"></i></div>
      </div>
    
  
</div>

      <div id="safearea">
        <div class="body-wrapper">
          
<div id="l_main" class=''>
  <article itemscope itemtype="http://schema.org/Article" class="article post white-box reveal md blur article-type-post" id="post" itemscope itemprop="blogPost">
  <link itemprop="mainEntityOfPage" href="https://cs0522.gitee.io/docs/atlantis-project/">
  <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
    <meta itemprop="name" content="诚实同学的博客">
  </span>
  <span hidden itemprop="post" itemscope itemtype="http://schema.org/Post">
    <meta itemprop="name" content="诚实同学的博客">
    <meta itemprop="description" content="Patience is key in life.">
  </span>
  


  
    <span hidden>
      <meta itemprop="image" content="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png">
    </span>
  
  <div class="article-meta" id="top">
    
    
    
      <h1 class="title" itemprop="name headline">
        【文档小记】Atlantis JMVT 游戏车队交流平台
      </h1>
      <div class='new-meta-box'>
        
          
            
<div class='new-meta-item author' itemprop="author" itemscope itemtype="http://schema.org/Person">
  <a itemprop="url" class='author' target="_blank" href="https://github.com/CS0522/" rel="nofollow noopener">
    <img itemprop="image" src="/images/userphoto/userphoto02.webp" class="lazyload" data-srcset="/images/userphoto/userphoto02.webp" srcset="">
    <p itemprop="name">Chen Shi</p>
  </a>
</div>

          
        
          
            
  <div class='new-meta-item category'>
    <i class="fa-solid fa-folder-open fa-fw" aria-hidden="true"></i>
    <a class="category-link" href="/categories/docs/">文档小记</a>
    
      <span hidden itemprop="about" itemscope itemtype="http://schema.org/Thing">
        <a href="/categories/docs/" itemprop="url"><span itemprop="name">文档小记</span></a>
      </span>
    
  </div>


          
        
          
            <div class="new-meta-item date" itemprop="dateCreated datePublished" datetime="2023-10-25T21:19:17+08:00">
  <a class='notlink'>
    <i class="fa-solid fa-calendar-alt fa-fw" aria-hidden="true"></i>
    <p>发布于：2023年10月25日</p>
  </a>
</div>

          
        
          
            
  <div class="new-meta-item wordcount">
    <a class='notlink'>
      <i class="fa-solid fa-keyboard fa-fw" aria-hidden="true"></i>
      <p>字数：5.3k 字</p>
    </a>
  </div>
  <div class="new-meta-item readtime">
    <a class='notlink'>
      <i class="fa-solid fa-hourglass-half fa-fw" aria-hidden="true"></i>
      <p>时长：26 分钟</p>
    </a>
  </div>


          
        
        <!-- Custom Files topMeta begin-->
        
        <!-- Custom Files topMeta end-->
      </div>
    
  </div>


  <div id="layoutHelper-page-plugins"></div>
  <div id="post-body" itemprop="articleBody">
    <p>记录了这个 Vue + SpringBoot 前后端项目开发的一些知识点以及解决方案</p>
<span id="more"></span>
<blockquote>
<p><a target="_blank" rel="noopener" href="https://github.com/CS0522/Atlantis">GitHub 项目地址</a></p>
</blockquote>
<div class="story post-story"><h2 id="基本介绍">基本介绍</h2>
<h3 id="springboot">SpringBoot</h3>
<ul>
<li>SpringBoot 是全新一代的 Spring 框架</li>
<li>开箱即用、预定优于配置、更轻量级</li>
<li>常用的第三方依赖整合（通过 Maven 子父工程的方式），简化 XML 配置，全部采用注解形式，内嵌 Web 应用容器</li>
<li>AOP 编程的支持（AOP 面向切面编程），功能增强，注解形式</li>
<li>IoC（Inversion of Control）控制反转</li>
<li>启动顺序
<ul>
<li>调用构造函数进行数据初始化</li>
<li>加载配置环境及上下文环境，返回应用配置上下文</li>
</ul></li>
</ul>
<h3 id="vue">vue</h3>
<ul>
<li>MVVM 设计模式</li>
<li>V：视图 view</li>
<li>ViewModel：一个同步 View 和 Model 的对象，连接 Model 和 View</li>
<li>M：模型 model，在其中定义数据修改和操作的业务逻辑</li>
<li>双向数据绑定，通过 ViewModel 进行交互，Model 和 ViewModel 之间的交互是双向的，因此 View 数据的变化会同步到 Model 中，而 Model 数据的变化也会立即反应到 View 上</li>
</ul>
<h3 id="mvcmvvm-和三层架构">MVC、MVVM 和三层架构</h3>
<ul>
<li>MVC（设计模式）<br />
MVC 通过分离 Model、View 和 Controller 的方式来组织代码结构。其中 View 负责页面的显示逻辑，Model 负责存储页面的业务数据，以及对相应数据的操作。并且 View 和 Model 应用了观察者模式，当 Model 层发生改变的时候它会通知有关 View 层更新页面。Controller 层是 View 层和 Model 层的纽带，它主要负责用户与应用的响应操作，当用户与页面产生交互的时候，Controller 中的事件触发器就开始工作了，通过调用 Model 层，来完成对 Model 的修改，然后 Model 层再去通知 View 层更新</li>
<li>MVVM<br />
Model 和 View 并无直接关联，而是通过 ViewModel 来进行联系的，Model 和 ViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新，View 中由于用户交互操作而改变的数据也会在 Model 中同步</li>
<li>三层架构（体系架构设计）
<ul>
<li>高内聚，低耦合</li>
<li>表现层、业务逻辑层、数据访问层（SpringMVC、Spring、MyBatis）</li>
</ul></li>
</ul>
<h3 id="项目介绍">项目介绍</h3>
<p>Atlantis Racer JMVT 网站是由游戏爱好者组建的 Atlantis Racer JMVT 车队的网站。该网站项目采用 Vue + SpringBoot 前后端分离技术，从 0 开始开发，90% 的功能或组件自主实现，其他功能或组件采用了第三方方案，引用了 Element-UI, github-markdown-css, mavon-editor, vuex 等。由于第一次接触 Vue 和 SpringBoot 等技术，边学习、边练习、边实践，因此项目中代码有很多地方冗余、复杂或有更为简单的方案实现，还能够继续优化。网站部署地址：http://atlantisracer.tk（挂）。</p>
<p>开发环境：</p>
<p>Windows 11 + VSCode (前端、后端) + IDEA (后端) + Edge + Apifox (接口测试) + MySQL Workbench (数据库) + Git</p>
<p>前后端请求路径：</p>
<p>前端访问：<code>localhost:8080</code></p>
<p>后端请求：</p>
<ul>
<li>localhost:8081/api</li>
<li>localhost:8082/api（于 <code>utils/baseUrl.js</code>，<code>controller/*/application.yml</code> 下修改）</li>
</ul>
<p>文件保存路径和数据库：</p>
<p>保存路径：</p>
<p>项目根目录 <code>/Data/&#123;photos|article_pictures&#125;/</code>（于 <code>com/atlantis/common/ProjectPath.java</code> 下修改）</p>
<p>测试用数据库：</p>
<p><code>TestSamples_DB.sql</code></p>
<p>实际使用数据库：</p>
<p><code>ForActualUse_DB.sql</code></p>
<p>实现的功能包括：</p>
<h3 id="数据库表关系">数据库表关系</h3>
<p><img src="./admin.png" class="lazyload" data-srcset="./admin.png" srcset="" /></p>
<p><img src="./user.png" class="lazyload" data-srcset="./user.png" srcset="" /></p>
<p><img src="./member.png" class="lazyload" data-srcset="./member.png" srcset="" /></p>
<p><img src="./apply-user_admin.png" class="lazyload" data-srcset="./apply-user_admin.png" srcset="" /></p>
<p><img src="./article-category.png" class="lazyload" data-srcset="./article-category.png" srcset="" /></p>
<h3 id="路由关系">路由关系</h3>
<p><img src="./route.png" class="lazyload" data-srcset="./route.png" srcset="" /></p>
<h3 id="总结">总结</h3>
<p>这次的项目开发，我们学习到了很多如：前端 Web 语言如 HTML、JavaScript、CSS 等；后端的语言 Java；前端的主流框架 Vue 和后端的主流框架 SpringBoot 相结合进行前后端的分离开发等。这些都是在理论课的基础上，进行知识的拓展和应用，让我们更进一步地了解企业中开发一个项目的大体流程，是宝贵的经验。</p>
</div><div class="story post-story"><h2 id="项目遇到的问题及解决方案">项目遇到的问题及解决方案</h2>
<h3 id="组件固定于浏览器某一位置">组件固定于浏览器某一位置：</h3>
<p>利用 <code>position: fixed</code> 属性固定。</p>
<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.top-bar</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">/* 设置边框为圆角 */</span></span><br><span class="line">    <span class="attribute">border-radius</span>: <span class="number">15px</span>;</span><br><span class="line">    <span class="attribute">float</span>: left;</span><br><span class="line">    <span class="attribute">text-align</span>: left;</span><br><span class="line">    <span class="comment">/* overflow: hidden; */</span></span><br><span class="line">    <span class="attribute">height</span>: <span class="number">150px</span>;</span><br><span class="line">    <span class="attribute">width</span>: auto;</span><br><span class="line">    <span class="comment">/* top bar始终处于浏览器顶端 */</span></span><br><span class="line">    <span class="attribute">position</span>: fixed;</span><br><span class="line">    <span class="comment">/* 设置top bar位置 */</span></span><br><span class="line">    <span class="attribute">top</span>: <span class="number">0cm</span>;</span><br><span class="line">    <span class="attribute">left</span>: <span class="number">1cm</span>;</span><br><span class="line">    <span class="attribute">right</span>: <span class="number">1cm</span>;</span><br><span class="line">    <span class="comment">/* border: solid; */</span></span><br><span class="line">    <span class="comment">/* 设置top bar背景色 */</span></span><br><span class="line">    <span class="attribute">background-color</span>: <span class="built_in">rgba</span>(<span class="number">252</span>, <span class="number">242</span>, <span class="number">241</span>, <span class="number">0.85</span>);</span><br><span class="line">    <span class="comment">/* 设置top bar阴影 */</span></span><br><span class="line">    <span class="attribute">box-shadow</span>: <span class="number">5px</span> <span class="number">15px</span> <span class="number">15px</span> <span class="number">5px</span> <span class="number">#888888</span>;</span><br><span class="line">    <span class="comment">/* 设置层级为1000，最大 */</span></span><br><span class="line">    <span class="attribute">z-index</span>: <span class="number">1000</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="禁止页面文字被复制">禁止页面文字被复制：</h3>
<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-id">#box</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="comment">/* 设置全局文字不能被选中 */</span></span><br><span class="line">  -webkit-user-select: none;</span><br><span class="line">  -moz-user-select: none;</span><br><span class="line">  -ms-user-select: none;</span><br><span class="line">  user-select: none;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="设置css作用范围">设置css作用范围：</h3>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">style</span> <span class="attr">scoped</span> <span class="attr">src</span>=<span class="string">&quot;@/../public/css/personalpage-style.css&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="未解决获取当前路由路径并映射为中文"><span style="color: red">（未解决）</span>获取当前路由路径并映射为中文：</h3>
<h3 id="路由跳转后页面不刷新">路由跳转后，页面不刷新：</h3>
<p>给 <code>router-view</code> 设置 <code>:key</code> 属性，路由改变，就会重新渲染。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">keep-alive</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">router-view</span> <span class="attr">v-if</span>=<span class="string">&quot;$route.meta.keepAlive&quot;</span> <span class="attr">:key</span>=<span class="string">&quot;$route.fullPath&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">router-view</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">keep-alive</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">router-view</span> <span class="attr">v-if</span>=<span class="string">&quot;!$route.meta.keepAlive&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">router-view</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="子组件子路由向父组件父路由传递参数">子组件（子路由）向父组件（父路由）传递参数：</h3>
<p>通过事件进行绑定，发生某个自定义事件，绑定一个方法，参数通过方法传递。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;dash-content-box&quot;</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 注意这个地方一定要绑定key！！！以后也是！！！ --&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 子组件传递参数，@绑定方法函数 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">router-view</span> <span class="attr">v-if</span>=<span class="string">&quot;isRouterAlive&quot;</span></span></span><br><span class="line"><span class="tag">                <span class="attr">:key</span>=<span class="string">&quot;$route.fullPath&quot;</span></span></span><br><span class="line"><span class="tag">                @<span class="attr">reload</span>=<span class="string">&quot;reload&quot;</span></span></span><br><span class="line"><span class="tag">                @<span class="attr">show-dialog</span>=<span class="string">&quot;showDialog&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">router-view</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">doOperation</span>(<span class="params">operation, contentType, objId</span>) &#123;</span><br><span class="line">    <span class="comment">// 修改vuex中的state数据</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">$store</span>.<span class="title function_">commit</span>(<span class="string">&#x27;setOperation&#x27;</span>, operation);</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">$store</span>.<span class="title function_">commit</span>(<span class="string">&#x27;setContentType&#x27;</span>, contentType);</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">$store</span>.<span class="title function_">commit</span>(<span class="string">&#x27;setObjId&#x27;</span>, objId);</span><br><span class="line">    <span class="comment">// 向父路由emit一个show-dialog事件</span></span><br><span class="line">    <span class="variable language_">this</span>.$emit(<span class="string">&#x27;show-dialog&#x27;</span>, <span class="literal">true</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="兄弟组件兄弟路由数据通信">兄弟组件（兄弟路由）数据通信：</h3>
<p>使用 <code>vuex</code> 即可。需要注意 <code>vuex</code> 在页面刷新后数据丢失，因此不要存储登录相关数据。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">Vue</span> <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">Vuex</span> <span class="keyword">from</span> <span class="string">&#x27;vuex&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="title class_">Vue</span>.<span class="title function_">use</span>(<span class="title class_">Vuex</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> store = <span class="keyword">new</span> <span class="title class_">Vuex</span>.<span class="title class_">Store</span>(&#123;</span><br><span class="line"><span class="comment">// vuex里的store刷新页面后内容会丢失</span></span><br><span class="line"><span class="attr">state</span>: &#123;</span><br><span class="line">    <span class="comment">// 用于DashContent子路由和AccountDialog之间的数据通信</span></span><br><span class="line">    <span class="attr">operation</span>: <span class="string">&#x27;&#x27;</span>,</span><br><span class="line">    <span class="attr">objId</span>: <span class="string">&#x27;&#x27;</span>,</span><br><span class="line">    <span class="attr">contentType</span>: <span class="string">&#x27;&#x27;</span>,</span><br><span class="line">    <span class="comment">// 保存CRUD操作类型，以及目标item的id</span></span><br><span class="line">    <span class="comment">// 登录成功后保存用户信息(X! vuex里的刷新后内容丢失)</span></span><br><span class="line">    <span class="comment">// accountInfo: &#123;&#125;,</span></span><br><span class="line">    <span class="comment">// isLogin: false,</span></span><br><span class="line">    <span class="comment">// loginType: &#x27;&#x27;,</span></span><br><span class="line">    <span class="comment">// admins, users</span></span><br><span class="line">&#125;,</span><br><span class="line"><span class="attr">mutations</span>: &#123;</span><br><span class="line">    <span class="title function_">setOperation</span>(<span class="params">state, newOperation</span>)&#123;</span><br><span class="line">        state.<span class="property">operation</span> = newOperation;</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="title function_">setObjId</span>(<span class="params">state, newId</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        state.<span class="property">objId</span> = newId;</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="title function_">setContentType</span>(<span class="params">state, newContentType</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        state.<span class="property">contentType</span> = newContentType;</span><br><span class="line">    &#125;,</span><br><span class="line">&#125;,</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> store</span><br></pre></td></tr></table></figure>
<h3 id="手动刷新子组件子路由">手动刷新子组件（子路由）：</h3>
<p>给子组件（子路由）设置 <code>v-if</code> 属性。自刷新可利用 <code>provide, inject</code> 注入函数依赖。刷新函数利用 <code>this.$nextTick(function() &#123;&#125;)</code> 改变绑定 <code>v-if</code> 的boolean变量的值。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 父组件内 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">TopBar</span> <span class="attr">v-if</span>=<span class="string">&quot;!topBarReload&quot;</span></span></span><br><span class="line"><span class="tag">        @<span class="attr">reload</span>=<span class="string">&quot;doTopBarReload()&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">TopBar</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">router-view</span> <span class="attr">v-if</span>=<span class="string">&quot;isRouterAlive&quot;</span></span></span><br><span class="line"><span class="tag">            <span class="attr">:key</span>=<span class="string">&quot;$route.fullPath&quot;</span></span></span><br><span class="line"><span class="tag">            @<span class="attr">reload</span>=<span class="string">&quot;reload&quot;</span></span></span><br><span class="line"><span class="tag">            @<span class="attr">show-dialog</span>=<span class="string">&quot;showDialog&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">router-view</span>&gt;</span></span><br></pre></td></tr></table></figure>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">data</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        <span class="attr">isShow</span>: <span class="literal">false</span>,</span><br><span class="line">        <span class="attr">isRouterAlive</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="attr">topBarReload</span>: <span class="literal">false</span>,</span><br><span class="line">    &#125;</span><br><span class="line">&#125;,</span><br><span class="line"><span class="comment">// 刷新路由操作</span></span><br><span class="line"><span class="title function_">provide</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        <span class="attr">reload</span>: <span class="variable language_">this</span>.<span class="property">reload</span>,</span><br><span class="line">        <span class="attr">doTopBarReload</span>: <span class="variable language_">this</span>.<span class="property">doTopBarReload</span>,</span><br><span class="line">    &#125;     </span><br><span class="line">&#125;,</span><br><span class="line"><span class="comment">// 刷新路由操作</span></span><br><span class="line"><span class="title function_">reload</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">isRouterAlive</span> = <span class="literal">false</span>;</span><br><span class="line">    <span class="variable language_">this</span>.$nextTick(<span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">isRouterAlive</span> = <span class="literal">true</span>;</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;,</span><br><span class="line"><span class="comment">// 刷新topbar</span></span><br><span class="line"><span class="title function_">doTopBarReload</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">topBarReload</span> = <span class="literal">true</span>;</span><br><span class="line">    <span class="variable language_">this</span>.$nextTick(<span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">topBarReload</span> = <span class="literal">false</span>;</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 子组件内</span></span><br><span class="line"><span class="comment">// 刷新路由操作，注入reload依赖</span></span><br><span class="line"><span class="attr">inject</span>: [<span class="string">&#x27;reload&#x27;</span>],</span><br></pre></td></tr></table></figure>
<h3 id="cors跨域">cors跨域：</h3>
<p>后端设置Config类，或者设置过滤器类。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Config class</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CorsConfig</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 当前跨域请求最大有效时长。1天</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">MAX_AGE</span> <span class="operator">=</span> <span class="number">24</span> * <span class="number">60</span> * <span class="number">60</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> CorsFilter <span class="title function_">corsFilter</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">UrlBasedCorsConfigurationSource</span> <span class="variable">source</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">UrlBasedCorsConfigurationSource</span>();</span><br><span class="line">        <span class="type">CorsConfiguration</span> <span class="variable">corsConfiguration</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CorsConfiguration</span>();</span><br><span class="line">        corsConfiguration.addAllowedOrigin(<span class="string">&quot;*&quot;</span>); <span class="comment">// 1 设置访问源地址</span></span><br><span class="line">        <span class="comment">// corsConfiguration addAllowedOriginsPattern(&quot;*&quot;);</span></span><br><span class="line">        corsConfiguration.addAllowedHeader(<span class="string">&quot;*&quot;</span>); <span class="comment">// 2 设置访问源请求头</span></span><br><span class="line">        corsConfiguration.addAllowedMethod(<span class="string">&quot;*&quot;</span>); <span class="comment">// 3 设置访问源请求方法</span></span><br><span class="line">        <span class="comment">// corsConfiguration.setAllowCredentials(true); // 解决前后的session对象不一致问题</span></span><br><span class="line">        corsConfiguration.setMaxAge(MAX_AGE);</span><br><span class="line">        source.registerCorsConfiguration(<span class="string">&quot;/**&quot;</span>, corsConfiguration); <span class="comment">// 4 对接口配置跨域设置</span></span><br><span class="line">        System.out.println(<span class="string">&quot;doing CORS config...&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">CorsFilter</span>(source);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// filter class. Need to add &#x27;ServletComponentScan&#x27; at Application class</span></span><br><span class="line"><span class="meta">@WebFilter(filterName = &quot;requestFilter&quot;, urlPatterns = &#123;&quot;/*&quot;&#125;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RequestFilter</span> <span class="keyword">implements</span> <span class="title class_">Filter</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">(FilterConfig filterConfig)</span> <span class="keyword">throws</span> ServletException &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doFilter</span><span class="params">(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain  filterChain)</span></span><br><span class="line">        <span class="keyword">throws</span> IOException, ServletException &#123;</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;doing request filter...&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="type">HttpServletResponse</span> <span class="variable">response</span> <span class="operator">=</span> (HttpServletResponse) servletResponse;</span><br><span class="line">        <span class="type">HttpServletRequest</span> <span class="variable">request</span> <span class="operator">=</span> (HttpServletRequest) servletRequest;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 此处 setHeader、addHeader 方法都可用。但 addHeader时写多个会报错：“...,but only one is allowed”</span></span><br><span class="line">        response.setHeader(<span class="string">&quot;Access-Control-Allow-Origin&quot;</span>, <span class="string">&quot;*&quot;</span>);</span><br><span class="line">        <span class="comment">// response.addHeader(&quot;Access-Control-Allow-Origin&quot;, request.getHeader(&quot;origin&quot;));</span></span><br><span class="line">        <span class="comment">// 解决预请求（发送2次请求），此问题也可在 nginx 中作相似设置解决。</span></span><br><span class="line">        response.setHeader(<span class="string">&quot;Access-Control-Allow-Headers&quot;</span>,</span><br><span class="line">                <span class="string">&quot;x-requested-with,Cache-Control,Pragma,Content-Type,Token, Content-Type&quot;</span>);</span><br><span class="line">        response.setHeader(<span class="string">&quot;Access-Control-Allow-Methods&quot;</span>, <span class="string">&quot;POST, GET, OPTIONS, PUT, DELETE&quot;</span>);</span><br><span class="line">        response.setHeader(<span class="string">&quot;Access-Control-Max-Age&quot;</span>, <span class="string">&quot;3600&quot;</span>);</span><br><span class="line">        response.setHeader(<span class="string">&quot;Access-Control-Allow-Credentials&quot;</span>, <span class="string">&quot;true&quot;</span>);</span><br><span class="line">        <span class="type">String</span> <span class="variable">method</span> <span class="operator">=</span> request.getMethod();</span><br><span class="line">        <span class="keyword">if</span> (method.equalsIgnoreCase(<span class="string">&quot;OPTIONS&quot;</span>)) &#123;</span><br><span class="line">            servletResponse.getOutputStream().write(<span class="string">&quot;Success&quot;</span>.getBytes(<span class="string">&quot;utf-8&quot;</span>));</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            filterChain.doFilter(servletRequest, servletResponse);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="cors跨域后session-id不一致">cors跨域后session id不一致：</h3>
<p><code>http://localhost:8080</code> 或 <code>http://172.16.12.103:8080</code> 只能成功一个。在 <code>application.yml</code> 中配置 Tomcat 监听ip地址。</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line"><span class="attr">port:</span> <span class="number">8081</span></span><br><span class="line"><span class="comment"># 内网ip, 部署后填入外网ip</span></span><br><span class="line"><span class="attr">address:</span> <span class="number">172.16</span><span class="number">.12</span><span class="number">.103</span></span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CorsConfig</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 当前跨域请求最大有效时长。1天</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">MAX_AGE</span> <span class="operator">=</span> <span class="number">24</span> * <span class="number">60</span> * <span class="number">60</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> CorsFilter <span class="title function_">corsFilter</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">UrlBasedCorsConfigurationSource</span> <span class="variable">source</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">UrlBasedCorsConfigurationSource</span>();</span><br><span class="line">        <span class="type">CorsConfiguration</span> <span class="variable">corsConfiguration</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CorsConfiguration</span>();</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;doing CORS config...&quot;</span>);</span><br><span class="line">        <span class="comment">// corsConfiguration.addAllowedOrigin(&quot;*&quot;); // 设置访问源地址</span></span><br><span class="line">        <span class="comment">//</span></span><br><span class="line">        corsConfiguration.addAllowedOriginPattern(<span class="string">&quot;**&quot;</span>);</span><br><span class="line">        corsConfiguration.addAllowedHeader(<span class="string">&quot;*&quot;</span>); <span class="comment">// 设置访问源请求头</span></span><br><span class="line">        corsConfiguration.addAllowedMethod(<span class="string">&quot;*&quot;</span>); <span class="comment">// 设置访问源请求方法</span></span><br><span class="line">        <span class="comment">//</span></span><br><span class="line">        corsConfiguration.setAllowCredentials(<span class="literal">true</span>); <span class="comment">// 解决前后的session对象不一致问题</span></span><br><span class="line"></span><br><span class="line">        corsConfiguration.setMaxAge(MAX_AGE);</span><br><span class="line">        source.registerCorsConfiguration(<span class="string">&quot;/**&quot;</span>, corsConfiguration); <span class="comment">// 对接口配置跨域设置</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">CorsFilter</span>(source);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> request = axios.<span class="title function_">create</span>(&#123;</span><br><span class="line">    <span class="attr">baseURL</span>: <span class="string">&#x27;http://172.16.12.103:8081&#x27;</span>,</span><br><span class="line">    <span class="attr">timeout</span>: <span class="number">5000</span>,</span><br><span class="line">    <span class="comment">// 解决前后session不一致问题</span></span><br><span class="line">    <span class="attr">withCredentials</span>: <span class="literal">true</span>,</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<h3 id="模块开发">模块开发：</h3>
<p>利用maven的继承和聚合。建立父工程，只包含 <code>pom.xml</code>，修改打包方式为 <code>pom</code>、声明子工程、统一设置依赖版本号以及子工程版本号。子工程内将 <code>&lt;parent&gt;</code> 设为父工程，<code>&lt;dependency&gt;</code> 中的依赖具有传递性。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 父工程中 --&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 修改打包方式 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">packaging</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">packaging</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 统一设置版本号 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">properties</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">java.version</span>&gt;</span>11<span class="tag">&lt;/<span class="name">java.version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">atlantis.version</span>&gt;</span>0.0.1-SNAPSHOT<span class="tag">&lt;/<span class="name">atlantis.version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">mybatis.version</span>&gt;</span>2.2.2<span class="tag">&lt;/<span class="name">mybatis.version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">mysql.version</span>&gt;</span>8.0.30<span class="tag">&lt;/<span class="name">mysql.version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">jackson.version</span>&gt;</span>2.13.4<span class="tag">&lt;/<span class="name">jackson.version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">druid.version</span>&gt;</span>1.2.13-SNSAPSHOT<span class="tag">&lt;/<span class="name">druid.version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">properties</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- dependency中进行引用 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>druid<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;druid.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 声明子工程 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">modules</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">module</span>&gt;</span>controller<span class="tag">&lt;/<span class="name">module</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">module</span>&gt;</span>mapper<span class="tag">&lt;/<span class="name">module</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">module</span>&gt;</span>pojo<span class="tag">&lt;/<span class="name">module</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">module</span>&gt;</span>service<span class="tag">&lt;/<span class="name">module</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">module</span>&gt;</span>util<span class="tag">&lt;/<span class="name">module</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">module</span>&gt;</span>exception<span class="tag">&lt;/<span class="name">module</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">module</span>&gt;</span>common<span class="tag">&lt;/<span class="name">module</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">module</span>&gt;</span>config<span class="tag">&lt;/<span class="name">module</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">module</span>&gt;</span>filter<span class="tag">&lt;/<span class="name">module</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">modules</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 子工程版本号 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependencyManagement</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.atlantis<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>mapper<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;atlantis.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.atlantis<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>pojo<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;atlantis.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencyManagement</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="代码重复进行复用">代码重复，进行复用：</h3>
<p>这个项目里，Java使用继承和泛型来减少代码重复；vue内主要重复的是axios请求，采用字符串拼接减少重复。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 关系：泛型ServiceImpl类实现泛型接口Service类。接口AdminService类继承泛型泛型接口Service类。AdminServiceImpl类继承泛型ServiceImp类，同时实现接口AdminService类。</span></span><br><span class="line"><span class="comment">// BaseService&lt;T&gt;</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">BaseService</span>&lt;T&gt; &#123;</span><br><span class="line">    <span class="keyword">public</span> T <span class="title function_">getById</span><span class="params">(Integer id)</span>;</span><br><span class="line">    <span class="keyword">public</span> List&lt;T&gt; <span class="title function_">getAll</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">insert</span><span class="params">(T obj)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">update</span><span class="params">(T obj)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">updateInfo</span><span class="params">(T obj)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">updatePwd</span><span class="params">(T obj)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">delete</span><span class="params">(Integer id)</span>;</span><br><span class="line">    <span class="keyword">public</span> T <span class="title function_">login</span><span class="params">(T login)</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// BaseServiceImpl&lt;T&gt;</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">BaseServiceImpl</span>&lt;T&gt; <span class="keyword">implements</span> <span class="title class_">BaseService</span>&lt;T&gt; &#123;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="comment">// 代理对象自动装配，SpringBoot无法识别</span></span><br><span class="line">    <span class="comment">// userDao实例可能会报错，修改检查配置</span></span><br><span class="line">    <span class="comment">// protected 子类可继承</span></span><br><span class="line">    <span class="keyword">protected</span> BaseMapper&lt;T&gt; baseMapper;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> T <span class="title function_">getById</span><span class="params">(Integer id)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> baseMapper.getById(id);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> List&lt;T&gt; <span class="title function_">getAll</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;T&gt;(baseMapper.getAll());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">insert</span><span class="params">(T obj)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">update</span><span class="params">(T obj)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> (baseMapper.update(obj) == <span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">updateInfo</span><span class="params">(T obj)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">updatePwd</span><span class="params">(T obj)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">delete</span><span class="params">(Integer id)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> (baseMapper.delete(id) == <span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> T <span class="title function_">login</span><span class="params">(T login)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// AdminService</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">AdminService</span> <span class="keyword">extends</span> <span class="title class_">BaseService</span>&lt;Admin&gt; &#123;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// AdminServiceImpl</span></span><br><span class="line"><span class="comment">// IoC容器管理对象</span></span><br><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AdminServiceImpl</span> <span class="keyword">extends</span> <span class="title class_">BaseServiceImpl</span>&lt;Admin&gt; <span class="keyword">implements</span> <span class="title class_">AdminService</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">updateInfo</span><span class="params">(Admin admin)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> (baseMapper.updateInfo(admin) == <span class="number">1</span>);</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">updatePwd</span><span class="params">(Admin admin)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> (baseMapper.updatePwd(admin) == <span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">insert</span><span class="params">(Admin admin)</span> &#123;</span><br><span class="line">        <span class="comment">// 查询数据库发现没有同名用户</span></span><br><span class="line">        <span class="keyword">if</span> (baseMapper.getByUsername(admin.getUsername()) == <span class="literal">null</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">return</span> (baseMapper.insert(admin) == <span class="number">1</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Admin <span class="title function_">login</span><span class="params">(Admin login)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> (baseMapper.getByUsernameAndPassword(login.getUsername(), login.getPassword()));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">load</span>(<span class="params"></span>) </span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// 拼接字符串，减少代码重复</span></span><br><span class="line">    <span class="keyword">let</span> typeStr = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">type</span> === <span class="string">&#x27;admin&#x27;</span>) &#123;</span><br><span class="line">        typeStr = <span class="string">&#x27;admins&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">type</span> === <span class="string">&#x27;user&#x27;</span>) &#123;</span><br><span class="line">        typeStr = <span class="string">&#x27;users&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (typeStr === <span class="string">&#x27;&#x27;</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// getAll请求，获取所有</span></span><br><span class="line">    request.<span class="title function_">get</span>(<span class="string">&quot;/&quot;</span> + typeStr).<span class="title function_">then</span>(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (res.<span class="property">code</span> === code.<span class="property">GET_OK</span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">items</span> = res.<span class="property">data</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(err)</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">$notify</span>.<span class="title function_">error</span>(&#123;</span><br><span class="line">            <span class="attr">title</span>: <span class="string">&#x27;获取失败&#x27;</span>,</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>
<h3 id="多个页面共用一个组件">多个页面共用一个组件：</h3>
<p>通过路径的变化，<code>props</code> 进行传参。<code>props</code> 内的参数JavaScript内无法直接获取，可以通过 <code>watch</code> 监听获得。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// personal page router</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="attr">path</span>: <span class="string">&quot;/personal&quot;</span>,</span><br><span class="line">    <span class="attr">redirect</span>: <span class="string">&quot;/personal/profile&quot;</span>,</span><br><span class="line">    <span class="attr">component</span>: <span class="title class_">Personal</span>,</span><br><span class="line">    <span class="comment">// meta: &#123;</span></span><br><span class="line">    <span class="comment">//     keepAlive: true // 需要缓存</span></span><br><span class="line">    <span class="comment">// &#125;,</span></span><br><span class="line">    <span class="comment">// props: true,</span></span><br><span class="line">    <span class="attr">children</span>: [</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="attr">path</span>: <span class="string">&quot;:type&quot;</span>,</span><br><span class="line">            <span class="attr">component</span>: <span class="title class_">PersonalContent</span>,</span><br><span class="line">            <span class="attr">props</span>: <span class="literal">true</span></span><br><span class="line">        &#125;</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 组件内</span></span><br><span class="line"><span class="attr">props</span>: [<span class="string">&#x27;type&#x27;</span>]</span><br></pre></td></tr></table></figure>
<h3 id="settimeout-延迟执行"><code>setTimeOut()</code> 延迟执行：</h3>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 延迟 300ms 刷新子路由</span></span><br><span class="line">  <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="title function_">reload</span>(); <span class="comment">// 执行方法</span></span><br><span class="line">  &#125;, <span class="number">300</span>);</span><br></pre></td></tr></table></figure>
<h3 id="用户头像上传下载">用户头像上传下载：</h3>
<p>利用 <code>ElementUI</code> 上传控件，并修改样式。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 界面 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">el-upload</span> </span></span><br><span class="line"><span class="tag">    <span class="attr">class</span> = <span class="string">&quot;avatar-uploader&quot;</span> </span></span><br><span class="line"><span class="tag">    <span class="attr">:action</span> = <span class="string">&quot;actionUrl&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">:show-file-list</span> = <span class="string">&quot;false&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">:on-success</span> = <span class="string">&quot;handleAvatarSuccess&quot;</span> </span></span><br><span class="line"><span class="tag">    <span class="attr">:before-upload</span> = <span class="string">&quot;beforeAvatarUpload&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">img</span> <span class="attr">v-if</span> = <span class="string">&quot;imageUrl&quot;</span> <span class="attr">:src</span> = <span class="string">&quot;imageUrl&quot;</span> <span class="attr">class</span> = <span class="string">&quot;avatar&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">i</span> <span class="attr">v-else</span> <span class="attr">class</span> = <span class="string">&quot;el-icon-plus avatar-uploader-icon&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">i</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">el-upload</span>&gt;</span></span><br></pre></td></tr></table></figure>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 用户头像上传</span></span><br><span class="line"><span class="title function_">handleAvatarSuccess</span>(<span class="params">res, file</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">imageUrl</span> = <span class="string">&quot;http://localhost:8081/users/download/&quot;</span> + <span class="variable language_">this</span>.<span class="property">userId</span>;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="title function_">reload</span>();</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">$notify</span>.<span class="title function_">success</span>(&#123;</span><br><span class="line">        <span class="attr">title</span>: <span class="string">&#x27;头像更新成功&#x27;</span></span><br><span class="line">    &#125;)</span><br><span class="line">&#125;,</span><br><span class="line"><span class="title function_">beforeAvatarUpload</span>(<span class="params">file</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (file) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;uploading...actionUrl: &quot;</span> + <span class="variable language_">this</span>.<span class="property">actionUrl</span>);</span><br><span class="line">        <span class="keyword">const</span> postfix = file.<span class="property">name</span>.<span class="title function_">split</span>(<span class="string">&#x27;.&#x27;</span>)[<span class="number">1</span>]</span><br><span class="line">        <span class="keyword">const</span> isSizeOk = file.<span class="property">size</span> &lt; (<span class="number">2</span> * <span class="number">1024</span> * <span class="number">1024</span>);</span><br><span class="line">        <span class="keyword">if</span> ([<span class="string">&#x27;png&#x27;</span>, <span class="string">&#x27;jpeg&#x27;</span>, <span class="string">&#x27;jpg&#x27;</span>].<span class="title function_">indexOf</span>(postfix) &lt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">$notify</span>.<span class="title function_">error</span>(&#123;</span><br><span class="line">                <span class="attr">title</span>: <span class="string">&#x27;头像仅支持 .png, .jpg, .jpeg 格式&#x27;</span></span><br><span class="line">            &#125;)</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">$refs</span>.<span class="property">upload</span>.<span class="title function_">clearFiles</span>()</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!isSizeOk) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">$notify</span>.<span class="title function_">error</span>(&#123;</span><br><span class="line">                <span class="attr">title</span>: <span class="string">&#x27;上传头像大小不能超过 2MB&#x27;</span></span><br><span class="line">            &#125;)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> file</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// basePath定义在 application.yml 配置文件中</span></span><br><span class="line"><span class="comment">// 用户的头像上传</span></span><br><span class="line"><span class="meta">@PostMapping(&quot;/upload/&#123;id&#125;&quot;)</span></span><br><span class="line"><span class="keyword">public</span> Result <span class="title function_">upload</span><span class="params">(MultipartFile file, <span class="meta">@PathVariable</span> Integer id)</span></span><br><span class="line">&#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;uploading...&quot;</span>);</span><br><span class="line">    <span class="comment">// 获取的file是临时文件，需要转存</span></span><br><span class="line"></span><br><span class="line">    <span class="type">File</span> <span class="variable">filePath</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">File</span>(basePath);</span><br><span class="line">    <span class="comment">// 若目录不存在，创建</span></span><br><span class="line">    <span class="keyword">if</span> (!filePath.exists())</span><br><span class="line">    &#123;</span><br><span class="line">        filePath.mkdirs();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 获取原始文件名后缀</span></span><br><span class="line">    <span class="comment">// String postfix = Objects.requireNonNull(</span></span><br><span class="line">    <span class="comment">//                    file.getOriginalFilename()).substring(</span></span><br><span class="line">    <span class="comment">//                            (file.getOriginalFilename().lastIndexOf(&quot;.&quot;)));</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 根据id重新生成用户名</span></span><br><span class="line">    <span class="comment">// 文件上传加入后缀 &#x27;.png&#x27;</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">fileName</span> <span class="operator">=</span> <span class="string">&quot;userId_&quot;</span> + id.toString() + <span class="string">&quot;.png&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 转存文件</span></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        file.transferTo(<span class="keyword">new</span> <span class="title class_">File</span>(basePath + fileName));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">SystemException</span>(<span class="string">&quot;upload failed&quot;</span>, e, Code.SYS_ERR);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Result</span>(Code.UPLOAD_OK, (String)fileName, <span class="string">&quot;upload succeeded&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 用户头像下载</span></span><br><span class="line"><span class="meta">@GetMapping(&quot;/download/&#123;id&#125;&quot;)</span></span><br><span class="line"><span class="keyword">public</span> Result <span class="title function_">download</span><span class="params">(HttpServletResponse response, <span class="meta">@PathVariable</span> Integer id)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">try</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">// 输入流读取文件内容</span></span><br><span class="line">        <span class="type">FileInputStream</span> <span class="variable">fis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileInputStream</span>(basePath + <span class="string">&quot;userId_&quot;</span> + id.toString() + <span class="string">&quot;.png&quot;</span>);</span><br><span class="line">        <span class="comment">// 输出流写回浏览器</span></span><br><span class="line">        <span class="type">ServletOutputStream</span> <span class="variable">sos</span> <span class="operator">=</span> response.getOutputStream();</span><br><span class="line">        response.setContentType(<span class="string">&quot;image/png&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> <span class="variable">len</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">        <span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">1024</span>];</span><br><span class="line">        <span class="keyword">while</span> ((len = fis.read(bytes)) != -<span class="number">1</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            sos.write(bytes, <span class="number">0</span>, len);</span><br><span class="line">            sos.flush();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//close</span></span><br><span class="line">        fis.close();</span><br><span class="line">        sos.close();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">catch</span> (Exception e)</span><br><span class="line">    &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Result</span>(Code.DOWNLOAD_ERR, <span class="literal">null</span>, <span class="string">&quot;no user photo&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Result</span>(Code.DOWNLOAD_OK,</span><br><span class="line">                    basePath + <span class="string">&quot;userId_&quot;</span> + id.toString() + <span class="string">&quot;.png&quot;</span>,</span><br><span class="line">                    <span class="string">&quot;download succeeded&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="分页查询">分页查询：</h3>
<p>利用 <code>ElementUI</code> 简化前端分页组件的开发；后端利用 <code>page-helper</code> 进行分页查询的业务层和控制层处理。</p>
<p>前端：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- pagination --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">el-pagination</span> <span class="attr">style</span>=<span class="string">&quot;zoom: 220%; margin-bottom: 20px&quot;</span></span></span><br><span class="line"><span class="tag">            @<span class="attr">size-change</span>=<span class="string">&quot;handleSizeChange&quot;</span> </span></span><br><span class="line"><span class="tag">            @<span class="attr">current-change</span>=<span class="string">&quot;handleCurrentChange&quot;</span> </span></span><br><span class="line"><span class="tag">            <span class="attr">:current-page.sync</span>=<span class="string">&quot;currentPage&quot;</span></span></span><br><span class="line"><span class="tag">            <span class="attr">:page-size</span>=<span class="string">&quot;pageSize&quot;</span> </span></span><br><span class="line"><span class="tag">            <span class="attr">layout</span>=<span class="string">&quot;prev, pager, next, jumper&quot;</span> </span></span><br><span class="line"><span class="tag">            <span class="attr">:total</span>=<span class="string">&quot;totalNumber&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">el-pagination</span>&gt;</span></span><br></pre></td></tr></table></figure>
<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.el-pager</span> <span class="selector-tag">li</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="attribute">background</span>: none <span class="meta">!important</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.el-pagination</span> <span class="selector-class">.btn-next</span>, <span class="selector-class">.el-pagination</span> <span class="selector-class">.btn-prev</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="attribute">background</span>: none <span class="meta">!important</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.el-pagination</span> <span class="selector-tag">button</span><span class="selector-pseudo">:disabled</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="attribute">background</span>: none <span class="meta">!important</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">data</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        <span class="comment">// for pagination</span></span><br><span class="line">        <span class="comment">// 当前页</span></span><br><span class="line">        <span class="attr">currentPage</span>: <span class="number">1</span>,</span><br><span class="line">        <span class="comment">// 每页条数</span></span><br><span class="line">        <span class="attr">pageSize</span>: <span class="number">10</span>,</span><br><span class="line">        <span class="comment">// 数据总数</span></span><br><span class="line">        <span class="attr">totalNumber</span>: <span class="number">0</span>,</span><br><span class="line">    &#125;</span><br><span class="line">&#125;,</span><br><span class="line"><span class="attr">methods</span>: &#123;</span><br><span class="line">    <span class="comment">// pagination</span></span><br><span class="line">    <span class="comment">// 页面条数修改时（没有设置这个功能）</span></span><br><span class="line">    <span class="title function_">handleSizeChange</span>(<span class="params">val</span>) &#123;</span><br><span class="line">        <span class="comment">// console.log(`每页 $&#123;val&#125; 条`);</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="title function_">handleCurrentChange</span>(<span class="params">val</span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;val: &quot;</span> + val);</span><br><span class="line">        request.<span class="title function_">get</span>(<span class="string">&quot;/&quot;</span> + <span class="variable language_">this</span>.<span class="property">typeStr</span> + <span class="string">&quot;/&quot;</span> + <span class="variable language_">this</span>.<span class="property">currentPage</span> + <span class="string">&quot;/&quot;</span> + <span class="variable language_">this</span>.<span class="property">pageSize</span>).<span class="title function_">then</span>(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (res.<span class="property">code</span> === code.<span class="property">GET_OK</span>) &#123;</span><br><span class="line">                <span class="comment">// 根据res的返回结果进行赋值</span></span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">items</span> = res.<span class="property">data</span>.<span class="property">list</span>;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">totalNumber</span> = res.<span class="property">data</span>.<span class="property">total</span>;</span><br><span class="line">                <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;currentpage after: &quot;</span> + <span class="variable language_">this</span>.<span class="property">currentPage</span>);</span><br><span class="line">                <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;total number: &quot;</span> + <span class="variable language_">this</span>.<span class="property">totalNumber</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(err)</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">$notify</span>.<span class="title function_">error</span>(&#123;</span><br><span class="line">                <span class="attr">title</span>: <span class="string">&#x27;获取失败&#x27;</span>,</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;)</span><br><span class="line">        <span class="comment">// console.log(`当前页: $&#123;val&#125;`);</span></span><br><span class="line">    &#125;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>后端：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// BaseService interface</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">BaseService</span>&lt;T&gt; &#123;</span><br><span class="line">    <span class="keyword">public</span> PageInfo&lt;T&gt; <span class="title function_">getAllByPage</span><span class="params">(<span class="type">int</span> pageNum, <span class="type">int</span> pageSize)</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// BaseServiceImpl </span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">BaseServiceImpl</span>&lt;T&gt; <span class="keyword">implements</span> <span class="title class_">BaseService</span>&lt;T&gt; &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> PageInfo&lt;T&gt; <span class="title function_">getAllByPage</span><span class="params">(<span class="type">int</span> pageNum, <span class="type">int</span> pageSize)</span> &#123;</span><br><span class="line">        PageHelper.startPage(pageNum, pageSize);</span><br><span class="line">        List&lt;T&gt; baseList = baseMapper.getAll();</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">PageInfo</span>&lt;T&gt;(baseList);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// BaseController</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">BaseController</span>&lt;T&gt; &#123;</span><br><span class="line">    <span class="meta">@GetMapping(&quot;/&#123;pageNum&#125;/&#123;pageSize&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> Result <span class="title function_">getAllByPage</span><span class="params">(<span class="meta">@PathVariable</span> Integer pageNum, <span class="meta">@PathVariable</span> Integer pageSize)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">try</span></span><br><span class="line">        &#123;</span><br><span class="line">            PageInfo&lt;T&gt; pageInfo = baseService.getAllByPage(pageNum, pageSize);</span><br><span class="line">            <span class="type">Integer</span> <span class="variable">code</span> <span class="operator">=</span> pageInfo != <span class="literal">null</span> ? Code.GET_OK : Code.GET_ERR;</span><br><span class="line">            <span class="type">String</span> <span class="variable">msg</span> <span class="operator">=</span> pageInfo != <span class="literal">null</span> ? <span class="string">&quot;get succeeded&quot;</span> : <span class="string">&quot;get failed&quot;</span>;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Result</span>(code, pageInfo, msg);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (SystemException e)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">SystemException</span>(<span class="string">&quot;unknown error occurred&quot;</span>, Code.SYS_ERR);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="搜索结果实时显示">搜索结果实时显示：</h3>
<p>使用 <code>watch:</code> 对 <code>&lt;input&gt;</code> 输入值进行监听。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 查询实时显示，watch监听</span></span><br><span class="line"><span class="attr">watch</span>: &#123;</span><br><span class="line">    <span class="comment">// 含输入的记得掐空格！！！</span></span><br><span class="line">    <span class="title function_">searchInput</span>(<span class="params">val</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (val.<span class="title function_">trim</span>() === <span class="string">&#x27;&#x27;</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">load</span>();</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 延迟 0.2s 进行实时显示</span></span><br><span class="line">        <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">            request.<span class="title function_">get</span>(<span class="string">&quot;/&quot;</span> + <span class="variable language_">this</span>.<span class="property">typeStr</span> + <span class="string">&quot;/&quot;</span> + val.<span class="title function_">trim</span>() + </span><br><span class="line">                    <span class="string">&quot;/&quot;</span> + <span class="variable language_">this</span>.<span class="property">currentPage</span> + <span class="string">&quot;/&quot;</span> + <span class="variable language_">this</span>.<span class="property">pageSize</span>).<span class="title function_">then</span>(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">                    <span class="keyword">if</span> (res.<span class="property">code</span> === code.<span class="property">GET_OK</span> &amp;&amp; res.<span class="property">data</span>.<span class="property">total</span>)</span><br><span class="line">                    &#123;</span><br><span class="line">                        <span class="variable language_">this</span>.<span class="property">items</span> = res.<span class="property">data</span>.<span class="property">list</span>;</span><br><span class="line">                        <span class="variable language_">this</span>.<span class="property">totalNumber</span> = res.<span class="property">data</span>.<span class="property">total</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="keyword">else</span> </span><br><span class="line">                    &#123;</span><br><span class="line">                        <span class="variable language_">this</span>.<span class="property">items</span> = [];</span><br><span class="line">                        <span class="variable language_">this</span>.<span class="property">totalNumber</span> = <span class="number">0</span>;</span><br><span class="line">                        <span class="variable language_">this</span>.<span class="property">$notify</span>.<span class="title function_">error</span>(&#123;</span><br><span class="line">                            <span class="attr">title</span>: message.<span class="property">FIND_ERR</span>,</span><br><span class="line">                        &#125;)</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">                    <span class="variable language_">this</span>.<span class="property">$notify</span>.<span class="title function_">error</span>(&#123;</span><br><span class="line">                        <span class="attr">title</span>: message.<span class="property">REQUEST_ERR</span>,</span><br><span class="line">                    &#125;)</span><br><span class="line">                &#125;)</span><br><span class="line">        &#125;, <span class="number">200</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>
<h3 id="浮动元素导致父元素高度塌陷">浮动元素导致父元素高度塌陷：</h3>
<p>添加以下css:</p>
<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.father</span></span><br><span class="line">&#123;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.son</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="attribute">float</span>: left;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.father</span><span class="selector-pseudo">::after</span> &#123;</span><br><span class="line"><span class="attribute">content</span>:<span class="string">&quot;&quot;</span>;</span><br><span class="line"><span class="comment">/*清除浮动*/</span></span><br><span class="line"><span class="attribute">clear</span>: both;</span><br><span class="line"><span class="comment">/*确保该元素是一个块级元素*/</span></span><br><span class="line"><span class="attribute">display</span>: block;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="localstorage过期时间">localStorage过期时间：</h3>
<p>封装了<code>localStorage</code>，在存储的同时将时间存进去。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// storage.js</span></span><br><span class="line"><span class="keyword">let</span> storage = &#123;</span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">    * set 存储方法</span></span><br><span class="line"><span class="comment">    * @ param &#123;String&#125;     key 键</span></span><br><span class="line"><span class="comment">    * @ param &#123;String&#125;     value 值，</span></span><br><span class="line"><span class="comment">    * @ param &#123;String&#125;     expired 过期时间，以毫秒为单位，非必须</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">    <span class="title function_">set</span>(<span class="params">key, val, expired</span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> obj = &#123;</span><br><span class="line">            <span class="attr">data</span>: val,</span><br><span class="line">            <span class="attr">time</span>: <span class="title class_">Date</span>.<span class="title function_">now</span>(),</span><br><span class="line">            expired</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="variable language_">localStorage</span>.<span class="title function_">setItem</span>(key, <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(obj));</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">    * get 获取方法</span></span><br><span class="line"><span class="comment">    * @ param &#123;String&#125;     key 键</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">    <span class="title function_">get</span>(<span class="params">key</span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> val = <span class="variable language_">localStorage</span>.<span class="title function_">getItem</span>(key);</span><br><span class="line">        <span class="keyword">if</span> (!val) &#123;</span><br><span class="line">            <span class="keyword">return</span> val;</span><br><span class="line">        &#125;</span><br><span class="line">        val = <span class="title class_">JSON</span>.<span class="title function_">parse</span>(val);</span><br><span class="line">        <span class="keyword">if</span> (<span class="title class_">Date</span>.<span class="title function_">now</span>() - val.<span class="property">time</span> &gt; val.<span class="property">expired</span>) &#123;</span><br><span class="line">            <span class="variable language_">localStorage</span>.<span class="title function_">removeItem</span>(key);</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> val.<span class="property">data</span>;</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">    * remove 删除方法</span></span><br><span class="line"><span class="comment">    * @ param &#123;String&#125;     key 键</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">    <span class="title function_">remove</span>(<span class="params">key</span>) &#123;</span><br><span class="line">        <span class="variable language_">localStorage</span>.<span class="title function_">removeItem</span>(key);</span><br><span class="line">    &#125;,</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> storage;</span><br><span class="line"><span class="comment">// main.js 中使用</span></span><br><span class="line"><span class="keyword">import</span> storage <span class="keyword">from</span> <span class="string">&#x27;./utils/storage.js&#x27;</span></span><br><span class="line"><span class="title class_">Vue</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">$storage</span>=storage;</span><br><span class="line"><span class="comment">// Vue组件中</span></span><br><span class="line"><span class="variable language_">this</span>.<span class="property">$storage</span>.<span class="title function_">set</span>(<span class="string">&#x27;item&#x27;</span>, item, <span class="number">24</span> * <span class="number">60</span> * <span class="number">60</span>);</span><br></pre></td></tr></table></figure>
<h3 id="解析-markdown-字符串">解析 <code>Markdown</code> 字符串：</h3>
<p>使用 <code>vue-markdown</code> 插件，并引入 <code>github-markdown-css</code> 文件。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">npm install vue-loader vue-template-compiler -D</span><br><span class="line">npm install --save vue-markdown</span><br><span class="line">npm install github-markdown-css</span><br></pre></td></tr></table></figure>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// main.js</span></span><br><span class="line"><span class="keyword">import</span> <span class="string">&#x27;github-markdown-css/github-markdown.css&#x27;</span></span><br></pre></td></tr></table></figure>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// vue组件内</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">VueMarkdown</span> <span class="keyword">from</span> <span class="string">&#x27;vue-markdown&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="attr">components</span>: &#123;</span><br><span class="line">    <span class="title class_">VueMarkdown</span> <span class="comment">// 注入组件</span></span><br><span class="line">  &#125;,</span><br><span class="line">  data () &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123; </span><br><span class="line">      <span class="attr">value</span>: <span class="title class_">MarkdownData</span> <span class="comment">// value的值是要解析的markdown数据</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- vue组件内 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;markdown-body&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">VueMarkdown</span> <span class="attr">:source</span>=<span class="string">&quot;value&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">VueMarkdown</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 可以自定义样式 */</span></span><br><span class="line"><span class="selector-class">.markdown-body</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="attribute">color</span>: <span class="number">#2c3e50</span>;</span><br><span class="line">    <span class="attribute">font-size</span>: <span class="number">30px</span>;</span><br><span class="line">    <span class="attribute">background-color</span>: <span class="built_in">rgba</span>(<span class="number">252</span>, <span class="number">242</span>, <span class="number">241</span>, <span class="number">0</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="mavon-editor-图片上传回显"><code>mavon-editor</code> 图片上传、回显：</h3>
<p><code>mavon-editor</code> 使用方法：<a target="_blank" rel="noopener" href="https://github.com/hinesboy/mavonEditor">mavon-editor</a></p>
<p><code>mavon-editor</code> 图片上传：<a target="_blank" rel="noopener" href="https://github.com/hinesboy/mavonEditor/blob/master/doc/cn/upload-images.md">pictures-upload</a></p>
<p>自定义 <code>imgAdd</code> 事件，后端设置上传接口；回显时设置 URL 磁盘映射，直接通过 URL 访问磁盘文件。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 前端</span></span><br><span class="line"><span class="comment">// 绑定@imgAdd event</span></span><br><span class="line">$imgAdd(pos, $file)&#123;</span><br><span class="line">    <span class="comment">// 第一步. 将图片上传到服务器.</span></span><br><span class="line">   <span class="keyword">var</span> formdata = <span class="keyword">new</span> <span class="title class_">FormData</span>();</span><br><span class="line">   formdata.<span class="title function_">append</span>(<span class="string">&#x27;file&#x27;</span>, $file);</span><br><span class="line">   <span class="comment">// request中的请求头是json格式，不方便</span></span><br><span class="line">   <span class="variable language_">this</span>.$axios(&#123;</span><br><span class="line">        <span class="attr">url</span>: <span class="variable language_">this</span>.<span class="property">$store</span>.<span class="property">state</span>.<span class="property">newsArticleImgBaseUrl</span> + <span class="string">&quot;upload&quot;</span>,</span><br><span class="line">        <span class="attr">method</span>: <span class="string">&#x27;post&#x27;</span>,</span><br><span class="line">        <span class="attr">data</span>: formdata,</span><br><span class="line">        <span class="attr">headers</span>: &#123; <span class="string">&#x27;Content-Type&#x27;</span>: <span class="string">&#x27;multipart/form-data&#x27;</span> &#125;,</span><br><span class="line">        <span class="attr">timeout</span>: <span class="number">5000</span>,</span><br><span class="line">        <span class="comment">// 解决前后session不一致问题</span></span><br><span class="line">        <span class="attr">withCredentials</span>: <span class="literal">true</span>,</span><br><span class="line">   &#125;).<span class="title function_">then</span>(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="comment">// 第二步. 将返回的url替换到文本原位置![...](0) -&gt; ![...](url)</span></span><br><span class="line">        <span class="keyword">let</span> result = <span class="title class_">JSON</span>.<span class="title function_">parse</span>(<span class="title class_">JSON</span>.<span class="title function_">stringify</span>(res));</span><br><span class="line">        <span class="comment">// console.log(&quot;result: &quot; + result);</span></span><br><span class="line">        <span class="keyword">if</span> (result.<span class="property">data</span>.<span class="property">code</span> === code.<span class="property">UPLOAD_OK</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">$refs</span>.<span class="property">md</span>.$img2Url(pos, </span><br><span class="line">                    <span class="variable language_">this</span>.<span class="property">$store</span>.<span class="property">state</span>.<span class="property">newsArticleImgBaseUrl</span> +<span class="string">&quot;download/&quot;</span> + result.<span class="property">data</span>.<span class="property">data</span>);</span><br><span class="line">        &#125;</span><br><span class="line">   &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 后端</span></span><br><span class="line"><span class="comment">// 上传，Controller层</span></span><br><span class="line"><span class="comment">// 文章内图片上传</span></span><br><span class="line"><span class="meta">@PostMapping(&quot;/upload&quot;)</span></span><br><span class="line"><span class="keyword">public</span> Result <span class="title function_">upload</span><span class="params">(MultipartFile file)</span></span><br><span class="line">&#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;uploading...&quot;</span>);</span><br><span class="line">    <span class="comment">// 获取的file是临时文件，需要转存</span></span><br><span class="line"></span><br><span class="line">    <span class="type">File</span> <span class="variable">filePath</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">File</span>(basePath);</span><br><span class="line">    <span class="comment">// 若目录不存在，创建</span></span><br><span class="line">    <span class="keyword">if</span> (!filePath.exists())</span><br><span class="line">    &#123;</span><br><span class="line">        filePath.mkdirs();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 获取原始文件名后缀</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">postfix</span> <span class="operator">=</span> Objects.requireNonNull(</span><br><span class="line">                        file.getOriginalFilename()).substring(</span><br><span class="line">                                (file.getOriginalFilename().lastIndexOf(<span class="string">&quot;.&quot;</span>)));</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 重新命名</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">fileName</span> <span class="operator">=</span> GenerateMD5.encrypt(file.getOriginalFilename()) + postfix;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 转存文件</span></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        file.transferTo(<span class="keyword">new</span> <span class="title class_">File</span>(basePath + fileName));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">SystemException</span>(<span class="string">&quot;upload failed&quot;</span>, e, Code.SYS_ERR);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Result</span>(Code.UPLOAD_OK, fileName, <span class="string">&quot;upload succeeded&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 下载，采用 URL 磁盘映射</span></span><br><span class="line"><span class="comment">// WebMvcConfig</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WebMvcConfig</span> <span class="keyword">extends</span> <span class="title class_">WebMvcConfigurerAdapter</span> &#123;</span><br><span class="line">    <span class="comment">// basePath 通过 application.yml 注入，是磁盘上的绝对路径</span></span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;atlantis.articlePicturesBasePath&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String basePath;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addResourceHandlers</span><span class="params">(ResourceHandlerRegistry registry)</span> &#123;</span><br><span class="line">        registry.addResourceHandler(<span class="string">&quot;/newsArticles/download/**&quot;</span>)</span><br><span class="line">                .addResourceLocations(<span class="string">&quot;file:&quot;</span> + basePath);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="div-元素内超过范围文字显示省略号"><code>&lt;div&gt;</code> 元素内超过范围文字显示省略号:</h3>
<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.div</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="attribute">width</span>: <span class="number">60%</span>;</span><br><span class="line">    <span class="attribute">text-align</span>: left;</span><br><span class="line">    <span class="attribute">overflow</span>: hidden;</span><br><span class="line">    <span class="attribute">text-overflow</span>: ellipsis;</span><br><span class="line">    <span class="attribute">white-space</span>: nowrap;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

</div>
  </div>
  
  
    
    <div class='footer'>
       <!-- 参考资料、相关资料等 -->
      
       <!-- 相关文章 -->
      
      <!-- 版权声明组件 -->
      
      <!-- 打赏组件 -->
      
    </div>
  
  
    


  <div class='article-meta' id="bottom">
    <div class='new-meta-box'>
      
        
          <div class="new-meta-item date" itemprop="dateModified" datetime="2023-11-12T10:56:03+08:00">
  <a class='notlink'>
    <i class="fa-solid fa-edit fa-fw" aria-hidden="true"></i>
    <p>最后更新于：2023年11月12日</p>
  </a>
</div>

        
      
        
          
  
  <div class="new-meta-item meta-tags"><a class="tag" href="/tags/Atlantis-JMVT/" rel="nofollow"><i class="fa-solid fa-hashtag fa-fw" aria-hidden="true"></i><p>Atlantis JMVT</p></a></div> <div class="new-meta-item meta-tags"><a class="tag" href="/tags/Vue/" rel="nofollow"><i class="fa-solid fa-hashtag fa-fw" aria-hidden="true"></i><p>Vue</p></a></div> <div class="new-meta-item meta-tags"><a class="tag" href="/tags/SpringBoot/" rel="nofollow"><i class="fa-solid fa-hashtag fa-fw" aria-hidden="true"></i><p>SpringBoot</p></a></div> <div class="new-meta-item meta-tags"><a class="tag" href="/tags/WebSite/" rel="nofollow"><i class="fa-solid fa-hashtag fa-fw" aria-hidden="true"></i><p>WebSite</p></a></div> <div class="new-meta-item meta-tags"><a class="tag" href="/tags/%E5%89%8D%E7%AB%AF/" rel="nofollow"><i class="fa-solid fa-hashtag fa-fw" aria-hidden="true"></i><p>前端</p></a></div> <div class="new-meta-item meta-tags"><a class="tag" href="/tags/%E5%90%8E%E7%AB%AF/" rel="nofollow"><i class="fa-solid fa-hashtag fa-fw" aria-hidden="true"></i><p>后端</p></a></div>
  <span hidden itemprop="keywords">Atlantis JMVT Vue SpringBoot WebSite 前端 后端</span>


        
      
        
          



        
      
        
          
  <div class="new-meta-item share -mob-share-list">
  <div class="-mob-share-list share-body">
    
      
        <a class="-mob-share-qq" title="" rel="external nofollow noopener noreferrer noopener"
          
          target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=https://cs0522.gitee.io/docs/atlantis-project/&title=【文档小记】Atlantis JMVT 游戏车队交流平台 - 诚实同学的博客&summary=记录了这个 Vue + SpringBoot 前后端项目开发的一些知识点以及解决方案"
          
          >
          
            <img src="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/qq.png" class="lazyload" data-srcset="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/qq.png" srcset="">
          
        </a>
      
    
      
        <a class="-mob-share-qzone" title="" rel="external nofollow noopener noreferrer noopener"
          
          target="_blank" href="https://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=https://cs0522.gitee.io/docs/atlantis-project/&title=【文档小记】Atlantis JMVT 游戏车队交流平台 - 诚实同学的博客&summary=记录了这个 Vue + SpringBoot 前后端项目开发的一些知识点以及解决方案"
          
          >
          
            <img src="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/qzone.png" class="lazyload" data-srcset="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/qzone.png" srcset="">
          
        </a>
      
    
      
        <a class="-mob-share-weibo" title="" rel="external nofollow noopener noreferrer noopener"
          
          target="_blank" href="http://service.weibo.com/share/share.php?url=https://cs0522.gitee.io/docs/atlantis-project/&title=【文档小记】Atlantis JMVT 游戏车队交流平台 - 诚实同学的博客&summary=记录了这个 Vue + SpringBoot 前后端项目开发的一些知识点以及解决方案"
          
          >
          
            <img src="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/weibo.png" class="lazyload" data-srcset="https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/logo/128/weibo.png" srcset="">
          
        </a>
      
    
      
    
      
    
  </div>
</div>



        
      
    </div>
    <!-- Custom Files bottomMeta begin -->
    
    <!-- Custom Files bottomMeta end -->
  </div>


  
  

  
    <div class="prev-next">
      
        <a class='prev' href='/notes/SimPy/simpy-learning-03/'>
          <p class='title'><i class="fa-solid fa-chevron-left" aria-hidden="true"></i>【学习笔记】SimPy 学习（三）：资源共享</p>
          <p class='content'>SimPy 的资源共享，Resource、Container、Store 等

仿真中涉及的人力资源以及工艺上的物料消耗都会抽象用 Resource 来表达，主要的 method 是 reque...</p>
        </a>
      
      
        <a class='next' href='/learnings/%E7%9B%98%E8%8A%82%E8%83%BD/thinraid/'>
          <p class='title'>【论文随记】230824_ThinRAID<i class="fa-solid fa-chevron-right" aria-hidden="true"></i></p>
          <p class='content'>本文针对数据中心的能源消耗问题，根据数据集大小使用部分磁盘建立 RAID 以节省能源

ThinRAID: Thinning Down RAID Array for Energy Conserv...</p>
        </a>
      
    </div>
  
  <!-- Custom Files postEnd begin-->
  
  <!-- Custom Files postEnd end-->
</article>




</div>
<aside id='l_side' itemscope itemtype="http://schema.org/WPSideBar">
  

  
    
    
      
    
  

  
    
    
      
<section class="widget desktop mobile pjax">
  
  <header>
    
      <i class="fa-solid fa-award fa-fw" aria-hidden="true"></i><span class='name'>站点信息</span>
    
  </header>


  <div class='content'>
    <div class="webinfo">
      
        <div class="webinfo-item">
          <div>文章数目：</div>
          <div>27 篇</div>
        </div>
      

      
        <div class="webinfo-item">
          <div>已运行时间：</div>
          <div id="webinfo-runtime-count"></div>
        </div>
      


      
        <div class="webinfo-item">
          <div>本站总字数：</div>
          <div>46.7k 字</div>
        </div>
      

      
        <div class="webinfo-item">
          <div>本站访客数：</div>
          
          <div><span id="busuanzi_value_site_uv"><i class="fa-solid fa-fan fa-spin fa-fw" aria-hidden="true"></i></span> 人</div>
          
        </div>
      

      
        <div class="webinfo-item">
          <div>本站总访问量：</div>
          
          <div><span id="busuanzi_value_site_pv"><i class="fa-solid fa-fan fa-spin fa-fw" aria-hidden="true"></i></span> 次</div>
          
        </div>
      

      
        <div class="webinfo-item">
          <div>最后活动时间：</div>
          <div id="last-update-show">2024-05-06 日</div>
        </div>
      
    </div>
  </div>
</section>

    
  


<div class="widget-sticky pjax">

  
  


  <section class="widget toc-wrapper desktop mobile " id="toc-div" >
    
  <header>
    
      <i class="fa-solid fa-list fa-fw" aria-hidden="true"></i><span class='name'>本文目录</span>
    
  </header>


    <div class='content'>
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%9F%BA%E6%9C%AC%E4%BB%8B%E7%BB%8D"><span class="toc-number">1.</span> <span class="toc-text">基本介绍</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#springboot"><span class="toc-number">1.1.</span> <span class="toc-text">SpringBoot</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#vue"><span class="toc-number">1.2.</span> <span class="toc-text">vue</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#mvcmvvm-%E5%92%8C%E4%B8%89%E5%B1%82%E6%9E%B6%E6%9E%84"><span class="toc-number">1.3.</span> <span class="toc-text">MVC、MVVM 和三层架构</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D"><span class="toc-number">1.4.</span> <span class="toc-text">项目介绍</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%95%B0%E6%8D%AE%E5%BA%93%E8%A1%A8%E5%85%B3%E7%B3%BB"><span class="toc-number">1.5.</span> <span class="toc-text">数据库表关系</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%B7%AF%E7%94%B1%E5%85%B3%E7%B3%BB"><span class="toc-number">1.6.</span> <span class="toc-text">路由关系</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%80%BB%E7%BB%93"><span class="toc-number">1.7.</span> <span class="toc-text">总结</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%A1%B9%E7%9B%AE%E9%81%87%E5%88%B0%E7%9A%84%E9%97%AE%E9%A2%98%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88"><span class="toc-number">2.</span> <span class="toc-text">项目遇到的问题及解决方案</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BB%84%E4%BB%B6%E5%9B%BA%E5%AE%9A%E4%BA%8E%E6%B5%8F%E8%A7%88%E5%99%A8%E6%9F%90%E4%B8%80%E4%BD%8D%E7%BD%AE"><span class="toc-number">2.1.</span> <span class="toc-text">组件固定于浏览器某一位置：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%A6%81%E6%AD%A2%E9%A1%B5%E9%9D%A2%E6%96%87%E5%AD%97%E8%A2%AB%E5%A4%8D%E5%88%B6"><span class="toc-number">2.2.</span> <span class="toc-text">禁止页面文字被复制：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%AE%BE%E7%BD%AEcss%E4%BD%9C%E7%94%A8%E8%8C%83%E5%9B%B4"><span class="toc-number">2.3.</span> <span class="toc-text">设置css作用范围：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9C%AA%E8%A7%A3%E5%86%B3%E8%8E%B7%E5%8F%96%E5%BD%93%E5%89%8D%E8%B7%AF%E7%94%B1%E8%B7%AF%E5%BE%84%E5%B9%B6%E6%98%A0%E5%B0%84%E4%B8%BA%E4%B8%AD%E6%96%87"><span class="toc-number">2.4.</span> <span class="toc-text">（未解决）获取当前路由路径并映射为中文：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%B7%AF%E7%94%B1%E8%B7%B3%E8%BD%AC%E5%90%8E%E9%A1%B5%E9%9D%A2%E4%B8%8D%E5%88%B7%E6%96%B0"><span class="toc-number">2.5.</span> <span class="toc-text">路由跳转后，页面不刷新：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AD%90%E7%BB%84%E4%BB%B6%E5%AD%90%E8%B7%AF%E7%94%B1%E5%90%91%E7%88%B6%E7%BB%84%E4%BB%B6%E7%88%B6%E8%B7%AF%E7%94%B1%E4%BC%A0%E9%80%92%E5%8F%82%E6%95%B0"><span class="toc-number">2.6.</span> <span class="toc-text">子组件（子路由）向父组件（父路由）传递参数：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%85%84%E5%BC%9F%E7%BB%84%E4%BB%B6%E5%85%84%E5%BC%9F%E8%B7%AF%E7%94%B1%E6%95%B0%E6%8D%AE%E9%80%9A%E4%BF%A1"><span class="toc-number">2.7.</span> <span class="toc-text">兄弟组件（兄弟路由）数据通信：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%89%8B%E5%8A%A8%E5%88%B7%E6%96%B0%E5%AD%90%E7%BB%84%E4%BB%B6%E5%AD%90%E8%B7%AF%E7%94%B1"><span class="toc-number">2.8.</span> <span class="toc-text">手动刷新子组件（子路由）：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#cors%E8%B7%A8%E5%9F%9F"><span class="toc-number">2.9.</span> <span class="toc-text">cors跨域：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#cors%E8%B7%A8%E5%9F%9F%E5%90%8Esession-id%E4%B8%8D%E4%B8%80%E8%87%B4"><span class="toc-number">2.10.</span> <span class="toc-text">cors跨域后session id不一致：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%A8%A1%E5%9D%97%E5%BC%80%E5%8F%91"><span class="toc-number">2.11.</span> <span class="toc-text">模块开发：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BB%A3%E7%A0%81%E9%87%8D%E5%A4%8D%E8%BF%9B%E8%A1%8C%E5%A4%8D%E7%94%A8"><span class="toc-number">2.12.</span> <span class="toc-text">代码重复，进行复用：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%A4%9A%E4%B8%AA%E9%A1%B5%E9%9D%A2%E5%85%B1%E7%94%A8%E4%B8%80%E4%B8%AA%E7%BB%84%E4%BB%B6"><span class="toc-number">2.13.</span> <span class="toc-text">多个页面共用一个组件：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#settimeout-%E5%BB%B6%E8%BF%9F%E6%89%A7%E8%A1%8C"><span class="toc-number">2.14.</span> <span class="toc-text">setTimeOut() 延迟执行：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%94%A8%E6%88%B7%E5%A4%B4%E5%83%8F%E4%B8%8A%E4%BC%A0%E4%B8%8B%E8%BD%BD"><span class="toc-number">2.15.</span> <span class="toc-text">用户头像上传下载：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%88%86%E9%A1%B5%E6%9F%A5%E8%AF%A2"><span class="toc-number">2.16.</span> <span class="toc-text">分页查询：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%90%9C%E7%B4%A2%E7%BB%93%E6%9E%9C%E5%AE%9E%E6%97%B6%E6%98%BE%E7%A4%BA"><span class="toc-number">2.17.</span> <span class="toc-text">搜索结果实时显示：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%B5%AE%E5%8A%A8%E5%85%83%E7%B4%A0%E5%AF%BC%E8%87%B4%E7%88%B6%E5%85%83%E7%B4%A0%E9%AB%98%E5%BA%A6%E5%A1%8C%E9%99%B7"><span class="toc-number">2.18.</span> <span class="toc-text">浮动元素导致父元素高度塌陷：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#localstorage%E8%BF%87%E6%9C%9F%E6%97%B6%E9%97%B4"><span class="toc-number">2.19.</span> <span class="toc-text">localStorage过期时间：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%A7%A3%E6%9E%90-markdown-%E5%AD%97%E7%AC%A6%E4%B8%B2"><span class="toc-number">2.20.</span> <span class="toc-text">解析 Markdown 字符串：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#mavon-editor-%E5%9B%BE%E7%89%87%E4%B8%8A%E4%BC%A0%E5%9B%9E%E6%98%BE"><span class="toc-number">2.21.</span> <span class="toc-text">mavon-editor 图片上传、回显：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#div-%E5%85%83%E7%B4%A0%E5%86%85%E8%B6%85%E8%BF%87%E8%8C%83%E5%9B%B4%E6%96%87%E5%AD%97%E6%98%BE%E7%A4%BA%E7%9C%81%E7%95%A5%E5%8F%B7"><span class="toc-number">2.22.</span> <span class="toc-text">&lt;div&gt; 元素内超过范围文字显示省略号:</span></a></li></ol></li></ol>
    </div>
  </section>

  

</div>


<!-- 没有 pjax 占位会报错 万恶的 pjax -->

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <div class="pjax">
    <!-- pjax占位 -->
  </div>

  <!-- Custom Files side begin -->
  
  <!-- Custom Files side end -->
</aside>



          <!--此文件用来存放一些不方便取值的变量-->
<!--思路大概是将值藏到重加载的区域内-->

<pjax>
<script>
  window.pdata={}
  pdata.ispage=true;
  pdata.commentPath="";
  pdata.commentPlaceholder="";
  pdata.commentConfig={};
  //  see: /layout/_partial/scripts/_ctrl/coverCtrl.ejs
  
    // header
    var l_header=document.getElementById("l_header");
    
    l_header.classList.add("show");
    
    
      // cover
      var cover_wrapper=document.querySelector('#l_cover .cover-wrapper');
      var scroll_down=document.getElementById('scroll-down');
      cover_wrapper.id="none";
      cover_wrapper.style.display="none";
      scroll_down.style.display="none";
    
  
</script>
</pjax>
        </div>
        
  
  <footer class="footer clearfix"  itemscope itemtype="http://schema.org/WPFooter">
    <br><br>
    
      
        <br>
        <div class="social-wrapper" itemprop="about" itemscope itemtype="http://schema.org/Thing">
          
            
              <a href="mailto:chenshi020522@outlook.com"
                class="social fa-solid fa-envelope flat-btn"
                target="_blank"
                rel="external nofollow noopener noreferrer" itemprop="url">
                
              </a>
            
          
            
              <a href="https://github.com/CS0522/"
                class="social fa-brands fa-github flat-btn"
                target="_blank"
                rel="external nofollow noopener noreferrer" itemprop="url">
                
              </a>
            
          
            
              <a href="/images/weixin.png"
                class="social fa-brands fa-weixin flat-btn"
                target="_blank"
                rel="external nofollow noopener noreferrer" itemprop="url">
                
              </a>
            
          
            
              <a href="/images/qq.jpg"
                class="social fa-brands fa-qq flat-btn"
                target="_blank"
                rel="external nofollow noopener noreferrer" itemprop="url">
                
              </a>
            
          
            
              <a href="https://space.bilibili.com/37047123/"
                class="social fa-brands fa-bilibili flat-btn"
                target="_blank"
                rel="external nofollow noopener noreferrer" itemprop="url">
                
              </a>
            
          
        </div>
      
    
      
    
      
        <div class='copyright'>
        <p>Copyright © Since 2023 诚实同学</p>

        </div>
      
    
    <!-- Custom Files footer begin-->
    
    <p style="font-size: .8125rem">本站采用 <a href="https://volantis.js.org/" target="_blank">Volantis</a> 主题设计</p>
    <!-- Custom Files footer end-->
  </footer>


        <a id="s-top" class="fa-solid fa-arrow-up fa-fw" href="/" onclick="return false;" title="top"></a>
      </div>
    </div>
    <div>
      <script>
  /******************** volantis.dom ********************************/
  // 页面选择器 将dom对象缓存起来 see: /source/js/app.js etc.
  volantis.dom.bodyAnchor = volantis.dom.$(document.getElementById("safearea")); // 页面主体
  volantis.dom.topBtn = volantis.dom.$(document.getElementById('s-top')); // 向上
  volantis.dom.wrapper = volantis.dom.$(document.getElementById('wrapper')); // 整个导航栏
  volantis.dom.coverAnchor = volantis.dom.$(document.querySelector('#l_cover .cover-wrapper')); // 1个
  volantis.dom.switcher = volantis.dom.$(document.querySelector('#l_header .switcher .s-search')); // 搜索按钮   移动端 1个
  volantis.dom.header = volantis.dom.$(document.getElementById('l_header')); // 移动端导航栏
  volantis.dom.search = volantis.dom.$(document.querySelector('#l_header .m_search')); // 搜索框 桌面端 移动端 1个
  volantis.dom.mPhoneList = volantis.dom.$(document.querySelectorAll('#l_header .m-phone .list-v')); //  手机端 子菜单 多个
</script>

<script>
  
  volantis.css("https://unpkg.com/volantis-static@0.0.1654736714924/libs/@fortawesome/fontawesome-pro/css/all.min.css");
  
  
  
</script>

<!-- required -->


<!-- internal -->

<script src="/js/app.js"></script>





  













<div id="rightmenu-wrapper">
  <ul class="list-v rightmenu" id="rightmenu-content">
    
  <li class='navigation menuNavigation-Content'>


    <a class="nav icon-only fix-cursor-default" onclick="history.back()"><i class="fa-duotone fa-arrow-left PETERRIVE fa-fw"></i></a>



    <a class="nav icon-only fix-cursor-default" onclick="history.forward()"><i class="fa-duotone fa-arrow-right PETERRIVE fa-fw"></i></a>



    <a class="nav icon-only fix-cursor-default" onclick="window.location.reload()"><i class="fa-duotone fa-redo PETERRIVE fa-fw"></i></a>



    <a class="nav icon-only fix-cursor-default" onclick="VolantisApp.scrolltoElement(volantis.dom.bodyAnchor)"><i class="fa-duotone fa-arrow-up PETERRIVE fa-fw"></i></a>


  </li>


    <hr class="menuLoad-Content" >



  <li class="menuLoad-Content">
    <span class="vlts-menu fix-cursor-default event" id="copyPaste" data-event="copyPaste" data-group="inputBox">
      <i class="fa-duotone PETERRIVE fa-paste fa-fw"></i>
      粘贴文本
    </span>
  </li>



  <li class="menuLoad-Content">
    <span class="vlts-menu fix-cursor-default event" id="copyAll" data-event="copyAll" data-group="inputBox">
      <i class="fa-duotone PETERRIVE fa-object-ungroup fa-fw"></i>
      全选文本
    </span>
  </li>



  <li class="menuLoad-Content">
    <span class="vlts-menu fix-cursor-default event" id="copyCut" data-event="copyCut" data-group="inputBox">
      <i class="fa-duotone PETERRIVE fa-cut fa-fw"></i>
      剪切文本
    </span>
  </li>



  <li class="menuLoad-Content">
    <span class="vlts-menu fix-cursor-default event" id="copyText" data-event="copyText" data-group="seletctText">
      <i class="fa-duotone PETERRIVE fa-copy fa-fw"></i>
      复制文本
    </span>
  </li>



  <li class="menuLoad-Content">
    <span class="vlts-menu fix-cursor-default event" id="searchWord" data-event="OpenSearch(__text__)" data-group="seletctText">
      <i class="fa-duotone PETERRIVE fa-search fa-fw"></i>
      站内搜索
    </span>
  </li>



  <li class="menuLoad-Content">
    <span class="vlts-menu fix-cursor-default event" id="bingSearch" data-event="window.open(`https://cn.bing.com/search?q=${__text__}`)" data-group="seletctText">
      <i class="fa-duotone PETERRIVE fa-search fa-fw"></i>
      必应搜索
    </span>
  </li>



  <li class="menuLoad-Content">
    <span class="vlts-menu fix-cursor-default event" id="openTab" data-event="window.open(__link__)" data-group="elementCheck">
      <i class="fa-duotone PETERRIVE fa-external-link-square-alt fa-fw"></i>
      新标签页打开
    </span>
  </li>



  <li class="menuLoad-Content">
    <span class="vlts-menu fix-cursor-default event" id="copyLink" data-event="copyLink" data-group="elementCheck">
      <i class="fa-duotone PETERRIVE fa-link fa-fw"></i>
      复制链接地址
    </span>
  </li>



  <li class="menuLoad-Content">
    <span class="vlts-menu fix-cursor-default event" id="copyImg" data-event="copyImg" data-group="elementImage">
      <i class="fa-duotone PETERRIVE fa-image fa-fw"></i>
      复制图片
    </span>
  </li>



  <li class="menuLoad-Content">
    <span class="vlts-menu fix-cursor-default event" id="googleImg" data-event="window.open(`https://www.google.com/searchbyimage?image_url=${__link__}`)" data-group="elementImage">
      <i class="fa-duotone PETERRIVE fa-images fa-fw"></i>
      谷歌识图
    </span>
  </li>



    <hr class="menuLoad-Content" >



  <li class="menuLoad-Content">
    <span class="vlts-menu fix-cursor-default event" id="prev" data-event="volantis.rightmenu.jump('prev')" data-group="prevNext">
      <i class="fa-duotone fa-angles-left PETERRIVE fa-fw"></i>
      查看上一篇
    </span>
  </li>



  <li class="menuLoad-Content">
    <span class="vlts-menu fix-cursor-default event" id="next" data-event="volantis.rightmenu.jump('next')" data-group="prevNext">
      <i class="fa-duotone fa-angles-right PETERRIVE fa-fw"></i>
      查看下一篇
    </span>
  </li>



    <hr class="menuLoad-Content" >



    <hr class="menuLoad-Content" >



  <li class="menuLoad-Content">
    <span class="vlts-menu fix-cursor-default event" id="darkMode" data-event="volantis.dark.toggle()" data-group="darkMode">
      <i class="fa-duotone fa-eclipse-alt WISTERIA fa-fw"></i>
      暗黑模式
    </span>
  </li>



    <hr class="menuLoad-Content" >



  <li class="menuLoad-Content">
    <span class="vlts-menu fix-cursor-default event" id="printMode" data-event="printMode" data-group="articlePage">
      <i class="fa-duotone fa-print TURQUOISE fa-fw"></i>
      打印页面
    </span>
  </li>



  <li class="menuLoad-Content">
    <span class="vlts-menu fix-cursor-default event" id="readMode" data-event="readMode" data-group="articlePage">
      <i class="fa-duotone fa-book-open EMERALD fa-fw"></i>
      阅读模式
    </span>
  </li>



    <hr class="menuLoad-Content" >


  </ul>
</div>
<script src="/js/plugins/rightMenus.js"></script>
<script>
  const RightMenusFunction = {};
  












  //RightMenusFunction['copyPaste'] = (fun) => {fun()}





  //RightMenusFunction['copyAll'] = (fun) => {fun()}





  //RightMenusFunction['copyCut'] = (fun) => {fun()}





  //RightMenusFunction['copyText'] = (fun) => {fun()}





  RightMenusFunction['searchWord'] = (__text__) => {OpenSearch(__text__)}





  RightMenusFunction['bingSearch'] = (__text__) => {window.open(`https://cn.bing.com/search?q=${__text__}`)}





  RightMenusFunction['openTab'] = (__link__) => {window.open(__link__)}





  //RightMenusFunction['copyLink'] = (fun) => {fun()}





  //RightMenusFunction['copyImg'] = (fun) => {fun()}





  RightMenusFunction['googleImg'] = (__link__) => {window.open(`https://www.google.com/searchbyimage?image_url=${__link__}`)}







  RightMenusFunction['prev'] = () => {volantis.rightmenu.jump('prev')}





  RightMenusFunction['next'] = () => {volantis.rightmenu.jump('next')}









  RightMenusFunction['darkMode'] = () => {volantis.dark.toggle()}







  //RightMenusFunction['printMode'] = (fun) => {fun()}





  //RightMenusFunction['readMode'] = (fun) => {fun()}





</script>



<!-- rightmenu要在darkmode之前（ToggleButton） darkmode要在comments之前（volantis.dark.push）-->

  <script>
const rootElement = document.documentElement;
const darkModeStorageKey = "color-scheme";
const rootElementDarkModeAttributeName = "color-scheme";
const setLS = (k, v) => {
    localStorage.setItem(k, v);
};
const removeLS = (k) => {
    localStorage.removeItem(k);
};
const getLS = (k) => {
    return localStorage.getItem(k);
};
const getModeFromCSSMediaQuery = () => {
  return window.matchMedia("(prefers-color-scheme: dark)").matches
    ? "dark"
    : "light";
};
const resetRootDarkModeAttributeAndLS = () => {
  rootElement.removeAttribute(rootElementDarkModeAttributeName);
  removeLS(darkModeStorageKey);
};
const validColorModeKeys = {
  dark: true,
  light: true,
};
const applyCustomDarkModeSettings = (mode) => {
  const currentSetting = mode || getLS(darkModeStorageKey);
  getCustomDarkMode();
  if (currentSetting === getModeFromCSSMediaQuery()) {
    resetRootDarkModeAttributeAndLS();
  } else if (validColorModeKeys[currentSetting]) {
    rootElement.setAttribute(rootElementDarkModeAttributeName, currentSetting);
  } else {
    resetRootDarkModeAttributeAndLS();
  }
};
const invertDarkModeObj = {
  dark: "light",
  light: "dark",
};
/**
 * get target mode
 */
 const getCustomDarkMode = () => {
  let currentSetting = getLS(darkModeStorageKey);
  if (validColorModeKeys[currentSetting]) {
    currentSetting = invertDarkModeObj[currentSetting];
  } else if (currentSetting === null) {
    currentSetting = invertDarkModeObj[getModeFromCSSMediaQuery()];
  } else {
    return;
  }
  if(currentSetting=="dark"){
    volantis.dark.mode="light";
  }else{
    volantis.dark.mode="dark";
  }
  // console.log(volantis.dark.mode)
};
const toggleCustomDarkMode = () => {
  let currentSetting = getLS(darkModeStorageKey);
  if (validColorModeKeys[currentSetting]) {
    currentSetting = invertDarkModeObj[currentSetting];
  } else if (currentSetting === null) {
    currentSetting = invertDarkModeObj[getModeFromCSSMediaQuery()];
  } else {
    return;
  }
  setLS(darkModeStorageKey, currentSetting);
  return currentSetting;
};
/**
 * 暗黑模式触发器
 */
volantis.dark.toggle=()=>{
  const mode = toggleCustomDarkMode();
  applyCustomDarkModeSettings(mode);
  // 使用 volantis.dark.push 方法传入volantis.dark.toggle回调函数 参见layout/_partial/scripts/global.ejs
  volantis.dark.method.toggle.start();
}
/**
 * bind event for toggle button
 */

function bindToggleButton() {
  var btn= document.querySelectorAll("#wrapper .toggle-mode-btn,#rightmenu-wrapper .toggle-mode-btn")
  btn.forEach(function (e) {
    volantis.dom.$(e).on('click',volantis.dark.toggle);
  })
}
applyCustomDarkModeSettings();
document.addEventListener("DOMContentLoaded", ()=>{
  volantis.requestAnimationFrame(bindToggleButton)
});
volantis.pjax.push(bindToggleButton);

const darkModelListeners={
  dark:(mediaQueryList )=>{
    if(mediaQueryList.matches){
      volantis.dark.mode = "dark";
    }
    volantis.dark.method.toggle.start();
  },
  light:(mediaQueryList)=>{
    if(mediaQueryList.matches){
      volantis.dark.mode = "light";
    }
    volantis.dark.method.toggle.start();
  }
}
window.matchMedia('(prefers-color-scheme: dark)').addListener(darkModelListeners.dark)
window.matchMedia('(prefers-color-scheme: light)').addListener(darkModelListeners.light)
</script>




<script>
  function loadIssuesJS() {
    
      const sites_api = document.getElementById('sites-api');
      if (sites_api != undefined && typeof SitesJS === 'undefined') {
        volantis.js("/js/plugins/tags/sites.js")
      }
    
    
      const friends_api = document.getElementById('friends-api');
      if (friends_api != undefined && typeof FriendsJS === 'undefined') {
        volantis.js("/js/plugins/tags/friends.js")
      }
    
    
      const contributors_api = document.getElementById('contributors-api');
      if (contributors_api != undefined && typeof ContributorsJS === 'undefined') {
        volantis.js("/js/plugins/tags/contributors.js")
      }
    
  };
  loadIssuesJS()
  volantis.pjax.push(()=>{
    loadIssuesJS();
  })

</script>




  <script defer src="https://unpkg.com/volantis-static@0.0.1654736714924/libs/vanilla-lazyload/dist/lazyload.min.js"></script>
<script>
  // https://www.npmjs.com/package/vanilla-lazyload
  // Set the options globally
  // to make LazyLoad self-initialize
  window.lazyLoadOptions = {
    elements_selector: ".lazyload",
    threshold: 0
  };
  // Listen to the initialization event
  // and get the instance of LazyLoad
  window.addEventListener(
    "LazyLoad::Initialized",
    function (event) {
      window.lazyLoadInstance = event.detail.instance;
    },
    false
  );
  document.addEventListener('DOMContentLoaded', function () {
    lazyLoadInstance.update();
  });
  document.addEventListener('pjax:complete', function () {
    lazyLoadInstance.update();
  });
</script>




  

<script>
  window.FPConfig = {
	delay: 0,
	ignoreKeywords: ["#"],
	maxRPS: 6,
	hoverDelay: 0
  };
</script>
<script defer src="https://unpkg.com/volantis-static@0.0.1654736714924/libs/flying-pages/flying-pages.min.js"></script>





   <script type="text/javascript">
  function pjax_scrollrebeal() {
    ScrollReveal().reveal("#l_main .reveal", {
      distance: "32px",
      duration: "800",
      interval: "20",
      scale: "1",
      easing: "ease-out",
    });
  }
  function init_scrollrebeal() {
    if (typeof ScrollReveal == "undefined") {
      volantis.requestAnimationFrame(init_scrollrebeal);
    } else {
      pjax_scrollrebeal();
    }
  }
  volantis.js("https://unpkg.com/volantis-static@0.0.1654736714924/libs/scrollreveal/dist/scrollreveal.min.js");
  document.addEventListener("DOMContentLoaded", init_scrollrebeal);
  volantis.pjax.push(
    pjax_scrollrebeal,
    "pjax_scrollrebeal",
    (setRequestAnimationFrame = false)
  );
</script>










  <script defer src="https://unpkg.com/volantis-static@0.0.1654736714924/libs/busuanzi/js/busuanzi.pure.mini.js" data-pjax></script>


<!-- optional -->

  <script>
  const SearchServiceDataPathRoot = ("/" || "/").endsWith("/") ?
    "/" || "/" :
    "//" || "/";
  const SearchServiceDataPath = SearchServiceDataPathRoot + "content.json";

  function loadSearchScript() {
    // see: layout/_partial/scripts/_ctrl/cdnCtrl.ejs
    return volantis.js("/js/search/hexo.js");
  }

  function loadSearchService() {
    loadSearchScript();
    document.querySelectorAll(".input.u-search-input").forEach((e) => {
      e.removeEventListener("focus", loadSearchService, false);
    });

    document.querySelectorAll(".u-search-form").forEach((e) => {
      e.addEventListener("submit", (event) => {
        event.preventDefault();
      }, false);
    });
  }

  // 打开并搜索 字符串 s
  function OpenSearch(s) {
    if (typeof SearchService === 'undefined')
      loadSearchScript().then(() => {
        SearchService.setQueryText(s);
        SearchService.search();
      });
    else {
      SearchService.setQueryText(s);
      SearchService.search();
    }
  }

  // 访问含有 ?s=xxx  的链接时打开搜索 // 与搜索引擎 structured data 相关: /scripts/helpers/structured-data/lib/config.js
  if (window.location.search && /^\?s=/g.test(window.location.search)) {
    let queryText = decodeURI(window.location.search)
      .replace(/\ /g, "-")
      .replace(/^\?s=/g, "");
    OpenSearch(queryText);
  }

  // 搜索输入框获取焦点时加载搜索
  document.querySelectorAll(".input.u-search-input").forEach((e) => {
    e.addEventListener("focus", loadSearchService, false);
  });
</script>







  <script>



  function pjax_highlightjs_copyCode(){
    if (!(document.querySelector(".highlight .code pre") ||
      document.querySelector(".article pre code"))) {
      return;
    }
    VolantisApp.utilCopyCode(".highlight .code pre, .article pre code")
  }
  volantis.requestAnimationFrame(pjax_highlightjs_copyCode)
  volantis.pjax.push(pjax_highlightjs_copyCode)

</script>










  <script>
  let imgs = ["/images/covers/cover08.webp","/images/covers/cover07.webp","/images/covers/cover05.webp","/images/covers/cover10.webp","/images/covers/cover06.webp","/images/covers/cover01.webp","/images/covers/cover04.webp","/images/covers/cover02.webp","/images/covers/cover03.webp","/images/covers/cover09.webp"];
  let index = 0;
  let IntervalParallax = null;

  function parallax(){
    let ParallaxWindow = document.querySelector("#parallax-window");
    
    Parallax.window = ParallaxWindow;
    Parallax.options.fade = 500;
    Parallax.cache = 1;
    next_parallax();
    Parallax.init();
    if (imgs.length>1) {
      IntervalParallax = setInterval(function () {
        next_parallax();
      }, '60000');
    }
  }

  function next_parallax() {
    if (typeof Parallax == "undefined") {
      return
    }
    
      if (!document.querySelector("#full")&&!document.querySelector("#half")) {
        return
      }
    
    if (imgs.length>=1) {
      Parallax.options.src = imgs[index % imgs.length];
      Parallax.start();
      index++;
      if (Parallax.cache) {
        fetch(imgs[index % imgs.length] +"?t=" + new Date().getTime());
        if (index == imgs.length) {
          Parallax.cache = 0;
        }
      }
    }
  }
  var runningOnBrowser = typeof window !== "undefined";
  var isBot = runningOnBrowser && !("onscroll" in window) || typeof navigator !== "undefined" && /(gle|ing|ro|msn)bot|crawl|spider|yand|duckgo/i.test(navigator.userAgent);
  if (!isBot) {
    volantis.js('/js/plugins/parallax.js').then(()=>{
      parallax()
    })
    volantis.pjax.send(()=>{
      clearInterval(IntervalParallax)
    },"clearIntervalParallax");
    volantis.pjax.push(parallax);
  }
</script>




  <script>
  function load_swiper() {
    if (!document.querySelectorAll(".swiper-container")[0]) return;
    volantis.css("https://unpkg.com/volantis-static@0.0.1654736714924/libs/swiper/swiper-bundle.min.css");
    volantis.js("https://unpkg.com/volantis-static@0.0.1654736714924/libs/swiper/swiper-bundle.min.js").then(() => {
      pjax_swiper();
    });
  }

  load_swiper();

  function pjax_swiper() {
    volantis.swiper = new Swiper('.swiper-container', {
      slidesPerView: 'auto',
      spaceBetween: 8,
      centeredSlides: true,
      loop: true,
      pagination: {
        el: '.swiper-pagination',
        clickable: true,
      },
      navigation: {
        nextEl: '.swiper-button-next',
        prevEl: '.swiper-button-prev',
      },
    });
  }

  volantis.pjax.push(() => {
    if (!document.querySelectorAll(".swiper-container")[0]) return;
    if (typeof volantis.swiper === "undefined") {
      load_swiper();
    } else {
      pjax_swiper();
    }
  });
</script>


<!-- pjax 标签必须存在于所有页面 否则 pjax error -->
<pjax>

</pjax>

<script>
  function listennSidebarTOC() {
    const navItems = document.querySelectorAll(".toc li");
    if (!navItems.length) return;
    let targets = []
    const sections = [...navItems].map((element) => {
      const link = element.querySelector(".toc-link");
      const target = document.getElementById(
        decodeURI(link.getAttribute("href")).replace("#", "")
      );
      targets.push(target)
      // 解除 a 标签 href 的 锚点定位, a 标签 href 的 锚点定位 会随机启用?? 产生错位???
      link.setAttribute("onclick","return false;")
      link.setAttribute("toc-action","toc-"+decodeURI(link.getAttribute("href")).replace("#", ""))
      link.setAttribute("href","/")
      // 配置 点击 触发新的锚点定位
      link.addEventListener("click", (event) => {
        event.preventDefault();
        // 这里的 addTop 是通过错位使得 toc 自动展开.
        volantis.scroll.to(target,{addTop: 5, observer:true})
        // Anchor id
        history.pushState(null, document.title, "#" + target.id);
      });
      return target;
    });

    function activateNavByIndex(target) {
      if (target.classList.contains("active-current")) return;

      document.querySelectorAll(".toc .active").forEach((element) => {
        element.classList.remove("active", "active-current");
      });
      target.classList.add("active", "active-current");
      let parent = target.parentNode;
      while (!parent.matches(".toc")) {
        if (parent.matches("li")) parent.classList.add("active");
        parent = parent.parentNode;
      }
    }

    // 方案一：
    volantis.activateNavIndex=0
    activateNavByIndex(navItems[volantis.activateNavIndex])
    volantis.scroll.push(()=>{
      if (targets[0].getBoundingClientRect().top >= 0) {
        volantis.activateNavIndex = 0
      }else if (targets[targets.length-1].getBoundingClientRect().top < 0) {
        volantis.activateNavIndex = targets.length-1
      } else {
        for (let index = 0; index < targets.length; index++) {
          const target0 = targets[index];
          const target1 = targets[(index+1)%targets.length];
          if (target0.getBoundingClientRect().top < 0&&target1.getBoundingClientRect().top >= 0) {
            volantis.activateNavIndex=index
            break;
          }
        }
      }
      activateNavByIndex(navItems[volantis.activateNavIndex])
    })

    // 方案二：
    // IntersectionObserver 不是完美精确到像素级别 也不是低延时性的
    // function findIndex(entries) {
    //   let index = 0;
    //   let entry = entries[index];
    //   if (entry.boundingClientRect.top > 0) {
    //     index = sections.indexOf(entry.target);
    //     return index === 0 ? 0 : index - 1;
    //   }
    //   for (; index < entries.length; index++) {
    //     if (entries[index].boundingClientRect.top <= 0) {
    //       entry = entries[index];
    //     } else {
    //       return sections.indexOf(entry.target);
    //     }
    //   }
    //   return sections.indexOf(entry.target);
    // }
    // function createIntersectionObserver(marginTop) {
    //   marginTop = Math.floor(marginTop + 10000);
    //   let intersectionObserver = new IntersectionObserver(
    //     (entries, observe) => {
    //       let scrollHeight = document.documentElement.scrollHeight;
    //       if (scrollHeight > marginTop) {
    //         observe.disconnect();
    //         createIntersectionObserver(scrollHeight);
    //         return;
    //       }
    //       let index = findIndex(entries);
    //       activateNavByIndex(navItems[index]);
    //     }, {
    //       rootMargin: marginTop + "px 0px -100% 0px",
    //       threshold: 0,
    //     }
    //   );
    //   sections.forEach((element) => {
    //     element && intersectionObserver.observe(element);
    //   });
    // }
    // createIntersectionObserver(document.documentElement.scrollHeight);
  }

  document.addEventListener("DOMContentLoaded", ()=>{
    volantis.requestAnimationFrame(listennSidebarTOC)
  });
  document.addEventListener("pjax:success", ()=>{
    volantis.requestAnimationFrame(listennSidebarTOC)
  });
</script>


  <script>
  try {
    // https://web.dev/content-visibility/
    // https://www.caniuse.com/?search=content-visibility
    // https://infrequently.org/2020/12/content-visibility-scroll-fix/
    // https://infrequently.org/2020/12/resize-resilient-deferred-rendering/

    // 备注 目前已知的问题:
    // 动态修改导致的内容高度变化(例如评论框异步渲染的外部盒子高度变化) 无法提前获知, 进而导致的首次滚动条跳动无法去除 (wontfix) 事实上不使用 content-visibility 也会有跳动, 不过是比使用 content-visibility 跳动提前
    // scrollreveal 插件潜在问题 目前尚不明确

    let eqIsh = (a, b, fuzz = 2) => {
      return Math.abs(a - b) <= fuzz;
    };

    let rectNotEQ = (a, b) => {
      return !eqIsh(a.width, b.width) || !eqIsh(a.height, b.height);
    };

    // Keep a map of elements and the dimensions of
    // their place-holders, re-setting the element's
    // intrinsic size when we get updated measurements
    // from observers.
    let spaced = new WeakMap();

    // Only call this when known cheap, post layout
    let reserveSpace = (el, rect = el.getClientBoundingRect()) => {
      let old = spaced.get(el);
      // Set intrinsic size to prevent jumping on un-painting:
      //    https://drafts.csswg.org/css-sizing-4/#intrinsic-size-override
      if (!old || rectNotEQ(old, rect)) {
        spaced.set(el, rect);
        el.style["contain-intrinsic-size"] = `${rect.width}px ${rect.height}px`;
      }
    };

    let iObs = new IntersectionObserver(
      (entries, o) => {
        entries.forEach((entry) => {
          // We don't care if the element is intersecting or
          // has been laid out as our page structure ensures
          // they'll get the right width.
          reserveSpace(entry.target, entry.boundingClientRect);
        });
      },
      { rootMargin: "500px 0px 500px 0px" }
    );

    let rObs = new ResizeObserver((entries, o) => {
      entries.forEach((entry) => {
        reserveSpace(entry.target, entry.contentRect);
      });
    });

    let resizeResilientDeferredRendering = (Selector) => {
      let articles = document.querySelectorAll(Selector);

      if (articles.length) {
        articles.forEach((el) => {
          iObs.observe(el);
          rObs.observe(el);
        });

        // Workaround for Chrome bug, part 2.
        //
        // Re-enable browser management of rendering for the
        // first article after the first paint. Double-rAF
        // to ensure we get called after a layout.
        requestAnimationFrame(() => {
          requestAnimationFrame(() => {
            articles[0].style["content-visibility"] = "auto";
          });
        });
      }
    };

    let contentVisibilityScrollFix = () => {
      if (!("content-visibility" in document.documentElement.style)) {
        return;
      }
      resizeResilientDeferredRendering(".post-story");
    };
    contentVisibilityScrollFix();
    volantis.pjax.push(contentVisibilityScrollFix);
  } catch (error) {
    console.log(error);
  }
</script>



<script>
  document.onreadystatechange = function () {
    if (document.readyState == 'complete') {
      // 页面加载完毕 样式加载失败，或是当前网速慢，或是开启了省流模式
      const { saveData, effectiveType } = navigator.connection || navigator.mozConnection || navigator.webkitConnection || {}
      if (getComputedStyle(document.querySelector("#safearea"), null)["display"] == "none" || saveData || /2g/.test(effectiveType)) {
        document.querySelectorAll(".reveal").forEach(function (e) {
          e.style["opacity"] = "1";
        });
        document.querySelector("#safearea").style["display"] = "block";
      }
    }
  }
</script>


  <script type="application/ld+json">[{"@context":"http://schema.org","@type":"Organization","name":"诚实同学的博客","url":"https://CS0522.gitee.io/","logo":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png","width":192,"height":192}},{"@context":"http://schema.org","@type":"Person","name":"Chen Shi","image":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png"},"url":"https://CS0522.gitee.io/","sameAs":["https://github.com/volantis-x"],"description":"Patience is key in life."},{"@context":"http://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"https://CS0522.gitee.io/","name":"诚实同学的博客"}},{"@type":"ListItem","position":2,"item":{"@id":"https://CS0522.gitee.io/categories/docs/","name":"文档小记"}},{"@type":"ListItem","position":3,"item":{"@id":"https://CS0522.gitee.io/ja-JP/docs/atlantis-project/","name":"【文档小记】Atlantis JMVT 游戏车队交流平台"}}]},{"@context":"http://schema.org","@type":"WebSite","name":"诚实同学的博客","url":"https://CS0522.gitee.io/","keywords":"个人博客, 计算机, 学习","description":"Patience is key in life.","author":{"@type":"Person","name":"Chen Shi","image":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png"},"url":"https://CS0522.gitee.io/","description":"Patience is key in life."},"publisher":{"@type":"Organization","name":"诚实同学的博客","url":"https://CS0522.gitee.io/","logo":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png","width":192,"height":192}},"potentialAction":{"@type":"SearchAction","name":"Site Search","target":{"@type":"EntryPoint","urlTemplate":"https://CS0522.gitee.io?s={search_term_string}"},"query-input":"required name=search_term_string"}},{"@context":"http://schema.org","@type":"BlogPosting","headline":"【文档小记】Atlantis JMVT 游戏车队交流平台","description":"记录了这个 Vue + SpringBoot 前后端项目开发的一些知识点以及解决方案","inLanguage":["zh-CN","en","ja-JP"],"mainEntityOfPage":{"@type":"WebPage","@id":"https://cs0522.gitee.io/docs/atlantis-project/"},"author":{"@type":"Person","name":"Chen Shi","image":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png"},"url":"https://CS0522.gitee.io/"},"publisher":{"@type":"Organization","name":"诚实同学的博客","logo":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png","width":192,"height":192}},"url":"https://cs0522.gitee.io/docs/atlantis-project/","wordCount":42,"datePublished":"2023-10-25T13:19:17.000Z","dateModified":"2023-11-12T02:56:03.720Z","articleSection":"文档小记","keywords":"Atlantis JMVT,Vue,SpringBoot,WebSite,前端,后端","image":{"@type":"ImageObject","url":"https://unpkg.com/volantis-static@0.0.1654736714924/media/org.volantis/blog/favicon/android-chrome-192x192.png","width":192,"height":192}}]</script>



      
        <!--
  pjax重载区域接口：
  1.  <pjax></pjax> 标签 pjax 标签必须存在于所有页面 否则 pjax error
  2.  script[data-pjax]
  3.  .pjax-reload script
  4.  .pjax
-->



<script src="https://unpkg.com/volantis-static@0.0.1654736714924/libs/pjax/pjax.min.js"></script>


<script>
    var pjax;
    document.addEventListener('DOMContentLoaded', function () {
      pjax = new Pjax({
        elements: 'a[href]:not([href^="#"]):not([href="javascript:void(0)"]):not([pjax-fancybox]):not([onclick="return false;"]):not([onclick="return!1"]):not([target="_blank"]):not([target="view_window"]):not([href$=".xml"])',
        selectors: [
          "head title",
          "head meta[name=keywords]",
          "head meta[name=description]",
          
          "#l_main",
          "#pjax-header-nav-list",
          ".pjax",
          "pjax", // <pjax></pjax> 标签
          "script[data-pjax], .pjax-reload script" // script标签添加data-pjax 或 script标签外层添加.pjax-reload 的script代码段重载
        ],
        cacheBust: false,   // url 地址追加时间戳，用以避免浏览器缓存
        timeout: 5000,
        
      });
    });

    document.addEventListener('pjax:send', function (e) {
      //window.stop(); // 相当于点击了浏览器的停止按钮

      try {
        var currentUrl = window.location.pathname;
        var targetUrl = e.triggerElement.href;
        var banUrl = [""];
        if (banUrl[0] != "") {
          banUrl.forEach(item => {
            if(currentUrl.indexOf(item) != -1 || targetUrl.indexOf(item) != -1) {
              window.location.href = targetUrl;
            }
          });
        }
      } catch (error) {}

      // 使用 volantis.pjax.send 方法传入pjax:send回调函数 参见layout/_partial/scripts/global.ejs
      volantis.pjax.method.send.start();
    });

    document.addEventListener('pjax:complete', function () {
      // 使用 volantis.pjax.push 方法传入重载函数 参见layout/_partial/scripts/global.ejs
      volantis.pjax.method.complete.start();
    });

    document.addEventListener('pjax:error', function (e) {
      if(volantis.debug) {
        console.error(e);
        console.log('pjax error: \n' + JSON.stringify(e));
      }else{
        // 使用 volantis.pjax.error 方法传入pjax:error回调函数 参见layout/_partial/scripts/global.ejs
        volantis.pjax.method.error.start();
        window.location.href = e.triggerElement.href;
      }
    });
</script>

      
    </div>
    <!-- import body_end begin-->
    <!-- import body_end end-->
    <!-- Custom Files bodyEnd begin-->
    
    <!-- Custom Files bodyEnd end-->
    <!-- front-matter body_end begin -->
    <!-- front-matter body_end end -->
  </body>
</html>
